Repository navigation
Closed
Closed
Copy link
Description
Is there an existing issue for this?
- I have checked for existing issues https://github.com/getsentry/sentry-javascript/issues
- I have reviewed the documentation https://docs.sentry.io/
- I am using the latest SDK release https://github.com/getsentry/sentry-javascript/releases
How do you use Sentry?
Sentry Saas (sentry.io)
Which SDK are you using?
@sentry/cloudflare - hono
SDK Version
10.7.0
Framework Version
Hono 4.9.4
Link to Sentry event
No response
Reproduction Example/SDK Setup
export default Sentry.withSentry(
(_env) => {
const env = checkBindings(_env)
const sentryEnabledEnvs: (typeof env.WORKER_ENVIRONMENT)[] = ["production", "staging"]
const enabled = sentryEnabledEnvs.includes(env.WORKER_ENVIRONMENT)
if (!enabled) console.info(`Sentry is disabled in env "${env.WORKER_ENVIRONMENT}"`)
const tracesSampleRate = env.WORKER_ENVIRONMENT === "production" ? 0.1 : 1
return {
dsn: env.SENTRY_DSN,
release: env.VERSION_ID,
sendDefaultPii: true,
environment: env.WORKER_ENVIRONMENT,
enableLogs: true,
tracesSampleRate,
enabled,
integrations: [
Sentry.consoleLoggingIntegration({ levels: ["log", "error", "warn"] }),
],
}
},
app,
)Steps to Reproduce
import { waitUntil } from "cloudflare:workers"
.get("/route", async (context) => {
// some business logic
async function updateDBAndCache() {
return Sentry.startSpan({ name: "Update DB and Cache" }, async () => {
const data = await updateDB()
await context.get("setMember")(data)
})
}
waitUntil(updateDBAndCache())
return context.json(result, 200)
})
.get("/route-with-error", async (context) => {
// some business logic
async function updateDBAndCache() {
return Sentry.startSpan({ name: "Update DB and Cache" }, async () => {
const data = await updateDB()
throw new Error("expected error")
await context.get("setMember")(data)
})
}
waitUntil(updateDBAndCache())
return context.json(result, 200)
})Expected Result
Span "Update DB and Cache" appears in Sentry as well as seeing the captured exception.
Actual Result
All spans and exceptions in waitUntil are lost.
Metadata
Metadata
Assignees
Projects
- StatusShow more project fieldsNo status
Activity
linear commentedon Aug 28, 2025
JS-889 Exceptions and Spans created or thrown in context.wailUntil() are not delivered to sentry
[-]Exceptions and Spans created or thrown in context.wailUntil() are not delivered to sentry[/-][+]Exceptions and Spans created or thrown in cloudflare workers context.wailUntil() are not delivered to sentry[/+][-]Exceptions and Spans created or thrown in cloudflare workers context.wailUntil() are not delivered to sentry[/-][+]Sentry does not capture errors or spans from Cloudflare Workers context.waitUntil()[/+]chargome commentedon Aug 29, 2025
Hey @the-leonat thanks for reaching out. As per docs I think you should rather use tail workers for this use case instead.
the-leonat commentedon Aug 29, 2025
I understand how to capture errors with tailworkers, but I’m looking for a way to instrument fetch calls and add tracing for calls inside
.waitUntil. From my understanding, tailworkers aren’t meant to run business logic, so persistence and cache updates should remain in the main worker.I briefly looked at the
sentry/cloudflaresource and noticed PR #16681, which seems related to my initial issue. Could you confirm whethersentry/cloudflareintends to support capturing spans and exceptions within.waitUntil, or if that isn’t currently supported?andreiborza commentedon Sep 1, 2025
Hi @the-leonat, we'll explore if it's feasible for us to capture spans and exceptions within
waitUntil.11 remaining items
JPeer264 commentedon Mar 11, 2026
Sorry that this got lost. This is actually a bigger problem. I already tried a few things the PR #18486 is explaining what is actually happening.
A small sum up: The problem is that internally we end our root span right after the request finishes. When
waitUntilproduces new spans directly after that, all these spans are lost. The solution would be to wait for #17836, which is a different technique how spans are send - which would solve this issue OOTB.We don't have an exact ETA for that, but we are heavily working on this.
JPeer264 commentedon Mar 13, 2026
There is actually a workaround that makes it possible today to capture everything within
waitUntil, but this needs to be added manually for now. You need to wrap it intoSentry.startSpanand setforceTransaction: true, theforceTransactionis actually the key part, which basically "splits" the request from thewaitUntil.Before:

After (

Subroutine in waitUntilis anotherSentry.startSpanwithinwaitUntil):Unfortunately we cannot instrument this on our end because of JavaScripts technical limitations. If we would instrument
waitUntilwe would get a pending promise and the spans, which would be inside from a code perspective, do have a different scope and therefore wrong parent (a more detailed reason is stated here).There is nothing we can do otherwise. I'll leave this ticket open until we have span streaming and this is confirmed to work properly with span streaming, but without the given workaround
the-leonat commentedon Mar 13, 2026
So the final instrumentation would look like this?
JPeer264 commentedon Mar 16, 2026
Your final instrumentation would look like this:
Also theoretically you don't need to have another span of "Update DB and Cache", unless you want of course, so you could simplify this even more:
fix(mcp-server): BL-032.76 — bypass @sentry/cloudflare on scheduled h…
JPeer264 commentedon Oct 5, 2026
Closing this as it is completed with opting in to span streaming which we introduced in
v10.49.0. And withv11.0.0we made it the default. Furthermore, in v11, we introduced a different way how clients are being created throughout the Cloudflare Workers lifespan (see #23083)