Describe the bug
NewRelic.Telemetry.Absinthe.handle_event/4 crashes with {:badmap, nil} whenever an Absinthe subscription registration runs through the pipeline. The handler is then auto-detached by :telemetry, which silently disables Absinthe transaction tracing for the rest of the OS process lifetime.
The issue is the assumption on lib/new_relic/telemetry/absinthe.ex:85:
def handle_event(@operation_stop, meas, meta, _config) do
operation = apply(Absinthe.Blueprint, :current_operation, [meta.blueprint])
span_name = operation_span_name(meta.blueprint.execution.result.emitter)
...
Absinthe.Phase.Telemetry emits [:absinthe, :execute, :operation, :stop] for all operations — queries, mutations, and the initial subscription registration. For subscriptions, Absinthe.Phase.Subscription.SubscribeSelf replaces the resolution phase with Absinthe.Phase.Subscription.Result, so blueprint.execution.result is nil (the subscription has not actually executed any field — it only registered a topic). The .emitter access then raises BadMapError.
Subsequent ongoing subscription publish events use a different telemetry event ([:absinthe, :subscription, :publish, :stop]), which the agent does not subscribe to — so this bug only surfaces at subscribe time, but it permanently disables operation tracing because :telemetry detaches the handler on the first error.
Stacktrace (production)
Handler {:new_relic, :absinthe} has failed and has been detached.
Class=:error
Reason={:badmap, nil}
Stacktrace=[
{NewRelic.Telemetry.Absinthe, :handle_event, 4,
[file: ~c"lib/new_relic/telemetry/absinthe.ex", line: 85]},
{:telemetry, :do_execute, 4,
[file: ~c"deps/telemetry/src/telemetry.erl", line: 202]},
{Absinthe.Phase.Telemetry, :do_run, 3,
[file: ~c"lib/absinthe/phase/telemetry.ex", line: 73]},
{Absinthe.Pipeline, :run_phase, 3,
[file: ~c"lib/absinthe/pipeline.ex", line: 411]},
{Absinthe.GraphqlWS.Transport, :run, 4,
[file: ~c"lib/absinthe/graphql_ws/transport.ex", line: 249]},
{Absinthe.GraphqlWS.Transport, :run_doc, 5,
[file: ~c"lib/absinthe/graphql_ws/transport.ex", line: 217]},
{Bandit.WebSocket.Connection, :handle_frame, 3,
[file: ~c"lib/bandit/websocket/connection.ex", line: 66]},
{Bandit.WebSocket.Handler, :pop_frame, 3,
[file: ~c"lib/bandit/websocket/handler.ex", line: 50]}
]
Repro outline
Any Absinthe schema with a subscription field + any client that drives a subscription document through Absinthe.Pipeline.run/2. We hit it via absinthe_graphql_ws over Bandit websockets — first incoming subscribe message reliably triggers it. A mix test ExUnit case calling Absinthe.run/2 with a subscription document on a schema attached to a Phoenix.PubSub should also reproduce.
Suggested fix
The crash is at the access; pattern-matching the operation type before reaching for .emitter is enough. For example:
def handle_event(@operation_stop, meas, meta, _config) do
operation = apply(Absinthe.Blueprint, :current_operation, [meta.blueprint])
case operation do
%{type: :subscription} ->
# Subscription registration emits :execute :operation :stop too,
# but execution.result is nil at this point (no field was
# resolved — only a topic was registered). Skip span emission;
# ongoing publishes are covered by :absinthe.subscription.publish.*.
:ok
_ ->
span_name = operation_span_name(meta.blueprint.execution.result.emitter)
transaction_name = transaction_name(meta.blueprint.schema, operation)
# ... existing body ...
end
end
Happy to send a PR if that direction is acceptable.
Environment
- Elixir & Erlang version: Elixir 1.19.5, Erlang/OTP 28.5
- Agent version:
new_relic_agent 1.40.2 (latest at the time of writing)
absinthe 1.10.2, absinthe_graphql_ws 0.3.6, absinthe_phoenix 2.0.5
phoenix 1.8.7, bandit 1.11.0, telemetry 1.4.1
Describe the bug
NewRelic.Telemetry.Absinthe.handle_event/4crashes with{:badmap, nil}whenever an Absinthe subscription registration runs through the pipeline. The handler is then auto-detached by:telemetry, which silently disables Absinthe transaction tracing for the rest of the OS process lifetime.The issue is the assumption on
lib/new_relic/telemetry/absinthe.ex:85:Absinthe.Phase.Telemetryemits[:absinthe, :execute, :operation, :stop]for all operations — queries, mutations, and the initial subscription registration. For subscriptions,Absinthe.Phase.Subscription.SubscribeSelfreplaces the resolution phase withAbsinthe.Phase.Subscription.Result, soblueprint.execution.resultisnil(the subscription has not actually executed any field — it only registered a topic). The.emitteraccess then raisesBadMapError.Subsequent ongoing subscription publish events use a different telemetry event (
[:absinthe, :subscription, :publish, :stop]), which the agent does not subscribe to — so this bug only surfaces at subscribe time, but it permanently disables operation tracing because:telemetrydetaches the handler on the first error.Stacktrace (production)
Repro outline
Any Absinthe schema with a
subscriptionfield + any client that drives a subscription document throughAbsinthe.Pipeline.run/2. We hit it viaabsinthe_graphql_wsover Bandit websockets — first incomingsubscribemessage reliably triggers it. Amix testExUnit case callingAbsinthe.run/2with a subscription document on a schema attached to aPhoenix.PubSubshould also reproduce.Suggested fix
The crash is at the access; pattern-matching the operation type before reaching for
.emitteris enough. For example:Happy to send a PR if that direction is acceptable.
Environment
new_relic_agent 1.40.2(latest at the time of writing)absinthe 1.10.2,absinthe_graphql_ws 0.3.6,absinthe_phoenix 2.0.5phoenix 1.8.7,bandit 1.11.0,telemetry 1.4.1