You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
An ArithmeticError occurs in ServeShapePlug.end_telemetry_span/2 when parse_body halts a request before start_telemetry_span has executed. The custom halt/1 unconditionally calls end_telemetry_span(), which attempts System.monotonic_time() - nil
This may be causing crashes - it is correlated with some electric container crashes, but I am not highly confident in this conclusion.
[error] ** (ArithmeticError) bad argument in arithmetic expression
:erlang.-(-576447606478025047, nil)
(electric 1.4.7) lib/electric/plug/serve_shape_plug.ex:286:
Electric.Plug.ServeShapePlug.end_telemetry_span/2
Root Cause
The plug pipeline order places parse_body (position 2) before start_telemetry_span (position 3):
plug:fetch_query_params# position 1plug:parse_body# position 2 - CAN HALT HEREplug:start_telemetry_span# position 3 - sets conn.private[:electric_telemetry_span]
Line 18 even has a comment: # start_telemetry_span needs to always be the first plug after fetching query params. — but parse_body sits between them.
When parse_body encounters an error (oversized body, bad JSON, etc.), it calls halt(). The custom halt/1 override (line 319-323) unconditionally calls end_telemetry_span(), which computes duration as:
Since start_telemetry_span never ran, conn.private[:electric_telemetry_span] is nil, so this evaluates to System.monotonic_time() - nil → ArithmeticError.
How to Reproduce
Send a POST request to any shape endpoint with a body exceeding the Plug read limit (default 8MB). Any of the 4 error paths in parse_body (lines 36-81) will trigger it:
Non-object JSON body (line 50-51)
Invalid JSON (line 57-64)
Body exceeds size limit (line 68-72) — this was the production trigger
The bug exists in every version from 1.4.0 onward (the first release containing PR #3777). The file has zero diff between @core/sync-service@1.4.0 and @core/sync-service@1.4.6 / HEAD.
Bug Description
An
ArithmeticErroroccurs inServeShapePlug.end_telemetry_span/2whenparse_bodyhalts a request beforestart_telemetry_spanhas executed. The customhalt/1unconditionally callsend_telemetry_span(), which attemptsSystem.monotonic_time() - nilThis may be causing crashes - it is correlated with some electric container crashes, but I am not highly confident in this conclusion.
Root Cause
The plug pipeline order places
parse_body(position 2) beforestart_telemetry_span(position 3):Line 18 even has a comment:
# start_telemetry_span needs to always be the first plug after fetching query params.— butparse_bodysits between them.When
parse_bodyencounters an error (oversized body, bad JSON, etc.), it callshalt(). The customhalt/1override (line 319-323) unconditionally callsend_telemetry_span(), which computes duration as:Since
start_telemetry_spannever ran,conn.private[:electric_telemetry_span]isnil, so this evaluates toSystem.monotonic_time() - nil→ArithmeticError.How to Reproduce
Send a POST request to any shape endpoint with a body exceeding the Plug read limit (default 8MB). Any of the 4 error paths in
parse_body(lines 36-81) will trigger it:Commits That Created This
841922d(Oct 2, 2024, PR chore(sync-service): Expand the set of OT span attributes assigned in ServeShapePlug #1736) — Introducedstart_telemetry_span,end_telemetry_span, and the customhalt/1override. At the time, all plugs that could halt were positioned afterstart_telemetry_span, so the assumption was safe.3f257aa(Jan 27, 2026, PR Add POST support for subset snapshots to avoid URL length limits #3777) — Addedparse_bodybeforestart_telemetry_spanin the pipeline, creating a code path wherehalt()→end_telemetry_span()runs without the span having been started.Key Code References
serve_shape_plug.ex:6—import Plug.Conn, except: [halt: 1]serve_shape_plug.ex:15-19— Pipeline ordering showingparse_bodybeforestart_telemetry_spanserve_shape_plug.ex:36-81—parse_body/2with 4 halt pathsserve_shape_plug.ex:268-272—start_telemetry_span/2setsconn.private[:electric_telemetry_span]serve_shape_plug.ex:286— The crash lineserve_shape_plug.ex:319-323— Customhalt/1that unconditionally callsend_telemetry_span()Affected Versions
The bug exists in every version from 1.4.0 onward (the first release containing PR #3777). The file has zero diff between
@core/sync-service@1.4.0and@core/sync-service@1.4.6/ HEAD.