Environment
- Current
develop, locally packed as @sentry/cloudflare 10.67.0
- Wrangler 4.123.0
- Cloudflare compatibility date
2026-08-13
traceLifecycle: 'static'
Problem
In the static trace lifecycle, the request transaction is assembled when the Worker handler returns. A child span which belongs to that request but ends later inside ExecutionContext.waitUntil() is not part of that snapshot and is never emitted independently.
The background work completes successfully and the Sentry client is still available. Only the span is lost.
This is distinct from #22545: the work is registered with waitUntil, rather than running as an untracked detached continuation.
Minimal reproduction
export default Sentry.withSentry(
env => ({
dsn: env.SENTRY_DSN,
tracesSampleRate: 1,
traceLifecycle: 'static',
}),
{
async fetch(_request, _env, context) {
const lateSpan = Sentry.startInactiveSpan({
name: 'late waitUntil child',
op: 'test.wait_until',
});
context.waitUntil(
new Promise(resolve => {
setTimeout(() => {
lateSpan.end();
resolve();
}, 25);
}),
);
return new Response(null, { status: 204 });
},
},
);
Actual behavior
Only the HTTP transaction is sent. The late child is absent from both the transaction and the remainder of the trace.
The behavior was reproduced locally from an exact SDK build and on a deployed Worker:
- A standard MCP request produced its HTTP, MCP, and child spans.
- A generic endpoint produced only its HTTP root; its late
waitUntil child was missing.
- A modern MCP
2026-07-28 request produced its HTTP and MCP spans; its late tool child was missing.
The generic endpoint confirms that this is a Cloudflare static-lifecycle problem, not an MCP protocol regression.
Expected behavior
A late child should be represented exactly once. If its segment transaction was already accepted, it should be emitted as a standalone transaction on the same trace, retaining its exact original parent and carrying sentry.parent_span_already_sent=true.
There must be no embedded-plus-standalone duplicate.
Additional context
Modern MCP 2026-07-28 exposed the problem because its stateless request can finish before background tool work. It is only a reproduction workload and control.
The legacy McpAgent path does not expose the same baseline because its tool spans use forceTransaction, making them independently capturable and masking this lifecycle gap.
Environment
develop, locally packed as@sentry/cloudflare10.67.02026-08-13traceLifecycle: 'static'Problem
In the static trace lifecycle, the request transaction is assembled when the Worker handler returns. A child span which belongs to that request but ends later inside
ExecutionContext.waitUntil()is not part of that snapshot and is never emitted independently.The background work completes successfully and the Sentry client is still available. Only the span is lost.
This is distinct from #22545: the work is registered with
waitUntil, rather than running as an untracked detached continuation.Minimal reproduction
Actual behavior
Only the HTTP transaction is sent. The late child is absent from both the transaction and the remainder of the trace.
The behavior was reproduced locally from an exact SDK build and on a deployed Worker:
waitUntilchild was missing.2026-07-28request produced its HTTP and MCP spans; its late tool child was missing.The generic endpoint confirms that this is a Cloudflare static-lifecycle problem, not an MCP protocol regression.
Expected behavior
A late child should be represented exactly once. If its segment transaction was already accepted, it should be emitted as a standalone transaction on the same trace, retaining its exact original parent and carrying
sentry.parent_span_already_sent=true.There must be no embedded-plus-standalone duplicate.
Additional context
Modern MCP
2026-07-28exposed the problem because its stateless request can finish before background tool work. It is only a reproduction workload and control.The legacy
McpAgentpath does not expose the same baseline because its tool spans useforceTransaction, making them independently capturable and masking this lifecycle gap.