Flue runs each agent in its own Durable Object, and nothing in the SDK runs Sentry.init() in that isolate. Users have to hand-write a wrapper module and re-export it from every agent module:
// src/sentry.ts
export const cloudflare = extend({
wrap: Final =>
Sentry.instrumentDurableObjectWithSentry((env: Env) => ({ dsn: env.SENTRY_DSN }), Final),
});
// src/agents/support.ts
export { cloudflare } from '../sentry.ts';
Miss the re-export in one agent module and that agent captures nothing, with no error anywhere. The Flue Cloudflare guide (getsentry/sentry-docs#19528) covers it with a warning and a troubleshooting entry, which is a weak fix for a silent failure.
Why auto-instrumentation doesn't cover it
sentryCloudflareAutoInstrumentPlugin is gated on wrangler's main, which resolveWranglerConfig reads from disk. Flue sets main to virtual:flue/worker and adds the DO bindings in memory, inside @cloudflare/vite-plugin's config hook, and never writes either to the file. Running wrangler's own reader against a real flue init app:
unstable_readConfig('<flue app>/wrangler.jsonc')
main : undefined
durable_objects.bindings : []
So entryFilePath is never assigned and transform returns on its first line (autoInstrument.ts:65). instrument.server.ts sits behind the same gate at autoInstrument.ts:51, so it is never probed either.
Contrast the cloudflare-mastra e2e app, whose wrangler.toml has main = "src/index.ts": a real file the user wrote that exports the classes. That is why Mastra works here and Flue does not.
Where to investigate
Flue's generated worker is a real module in the graph, and it exports each agent class from a fixed shape:
export const FlueHelloAgent = createFlueAgentClass({
AgentBase: Agent,
className: "FlueHelloAgent",
extension: Reflect.get(__flue_agent_module_0__, 'cloudflare'),
});
Wrapping the result there looks viable. Open questions:
- Where options come from.
getFinalOptions already reads env.SENTRY_DSN (options.ts:68), so the env fallback may be enough and the setup could end up zero-config. An instrument.server.* probe would need a directory to start from, since there is no real main to sit next to.
- Not double-wrapping. Anyone on the documented setup applies the wrapper inside
createFlueAgentClass, which the build cannot see. _INTERNAL_wrapUnlessInstrumented (instrument.ts:96) was built for this case; confirm it covers it before relying on it.
- Which wrapper. Flue builds the class with
AgentBase: Agent from agents, so it is a real Agent rather than a plain Durable Object. instrumentAgentWithSentry may apply and carry more than instrumentDurableObjectWithSentry.
- Failing loudly. The generated module is marked "Do not edit" and is not API. A transform that matches it should warn when it finds no
createFlueAgentClass call, rather than silently shipping an uninstrumented worker.
One thing to rule out up front: do not reuse the extension slot. resolveCloudflareExtension reads exactly one cloudflare export per agent, with no array and no registry, so taking it would clobber a user's own extension.
Flue runs each agent in its own Durable Object, and nothing in the SDK runs
Sentry.init()in that isolate. Users have to hand-write a wrapper module and re-export it from every agent module:Miss the re-export in one agent module and that agent captures nothing, with no error anywhere. The Flue Cloudflare guide (getsentry/sentry-docs#19528) covers it with a warning and a troubleshooting entry, which is a weak fix for a silent failure.
Why auto-instrumentation doesn't cover it
sentryCloudflareAutoInstrumentPluginis gated on wrangler'smain, whichresolveWranglerConfigreads from disk. Flue setsmaintovirtual:flue/workerand adds the DO bindings in memory, inside@cloudflare/vite-plugin'sconfighook, and never writes either to the file. Running wrangler's own reader against a realflue initapp:So
entryFilePathis never assigned andtransformreturns on its first line (autoInstrument.ts:65).instrument.server.tssits behind the same gate atautoInstrument.ts:51, so it is never probed either.Contrast the
cloudflare-mastrae2e app, whosewrangler.tomlhasmain = "src/index.ts": a real file the user wrote that exports the classes. That is why Mastra works here and Flue does not.Where to investigate
Flue's generated worker is a real module in the graph, and it exports each agent class from a fixed shape:
Wrapping the result there looks viable. Open questions:
getFinalOptionsalready readsenv.SENTRY_DSN(options.ts:68), so the env fallback may be enough and the setup could end up zero-config. Aninstrument.server.*probe would need a directory to start from, since there is no realmainto sit next to.createFlueAgentClass, which the build cannot see._INTERNAL_wrapUnlessInstrumented(instrument.ts:96) was built for this case; confirm it covers it before relying on it.AgentBase: Agentfromagents, so it is a real Agent rather than a plain Durable Object.instrumentAgentWithSentrymay apply and carry more thaninstrumentDurableObjectWithSentry.createFlueAgentClasscall, rather than silently shipping an uninstrumented worker.One thing to rule out up front: do not reuse the
extensionslot.resolveCloudflareExtensionreads exactly onecloudflareexport per agent, with no array and no registry, so taking it would clobber a user's own extension.