Framework guide
Error tracking for Cloudflare Workers
@belvador/cloudflare wraps a Worker so errors in its handlers are reported while responses stay exactly as your code returns them. Each invocation gets its own scope, so user, tags and context never leak between requests.
The short answer#
Wrap the exported Worker with
withBelvadorfrom@belvador/cloudflare.Errors in
fetch,scheduled,queue,emailandtailhandlers are reported; responses are unchanged.Sending happens in
ctx.waitUntilafter the response.Requires the
nodejs_compatflag; Durable Object classes are not wrapped in 0.x.
Install#
npm install @belvador/cloudflare@0.6.1Wrap the Worker#
import { withBelvador } from "@belvador/cloudflare";type Env = { BELVADOR_DSN?: string; BELVADOR_RELEASE?: string };// Requires the nodejs_compat compatibility flag.// The DSN comes from env.BELVADOR_DSN when you leave it out here.export default withBelvador( (env: Env) => ({ dsn: env.BELVADOR_DSN ?? "https://<public-key>@ingest.belvador.dev/<project-id>", release: env.BELVADOR_RELEASE, }), { async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> { return new Response("ok"); }, },);Enable the nodejs_compat compatibility flag in wrangler.jsonc; it is what gives every invocation its own scope (Cloudflare guide).
Scheduled handlers#
A Worker's scheduled handler is a cron job like any other. Report it with a check-in so a run that never fires opens an incident:
import { withBelvador, withMonitor } from "@belvador/cloudflare";export default withBelvador((env: Env) => ({ release: env.BELVADOR_RELEASE }), { async scheduled(controller, env, ctx) { await withMonitor("nightly-invoices", async (run) => { // Your job. Nothing to do? run.skip("nothing_due") }, { schedule: { type: "crontab", value: "0 2 * * *" }, timezone: "UTC" }); },});See cron monitoring for schedules, results and alerts.
Traces and logs#
Workers can export OpenTelemetry traces and logs to Belvador; the guide covers Cloudflare's built-in export and the SDK route (OpenTelemetry for Workers).
Not tested yet: this setup follows the vendor's documentation; Belvador has not run it end to end.
Limits#
Module syntax (
export default { fetch … }) deployed with Wrangler. Service-worker syntax is not supported.withBelvadorwraps thefetch,scheduled,queue,emailandtailhandlers of the exported object. Durable Object classes are not wrapped in 0.x; callcaptureExceptionin them.For TanStack Start or Lovable apps, use the TanStack Start package, which includes this one.
Questions#
Does wrapping change my responses or add latency to them?#
Responses are returned exactly as your code builds them. Sending finishes after the response, in ctx.waitUntil, so it does not delay the visitor.
Posts on this topic
All posts- Monitoring AI agents that run on serverless functionsAn AI agent on serverless is a chain of short functions with hard time limits. What to monitor at each step, with three lab runs and documented limits.
- Cloudflare Workers error tracking: the errors that still return 200A test Worker failing five ways, three runs each: what the client, Cloudflare's Tail and an error-tracking wrapper saw, and how to catch waitUntil errors.
Try it on your own Hetzner project
Free during the beta. Hetzner bills the server; Belvador never bills per event.