Skip to content

types: add WorkersRpcError and DurableObjectError interfaces#6604

Open
dmmulroy wants to merge 1 commit intocloudflare:mainfrom
dmmulroy:dillon/durable-object-error-type
Open

types: add WorkersRpcError and DurableObjectError interfaces#6604
dmmulroy wants to merge 1 commit intocloudflare:mainfrom
dmmulroy:dillon/durable-object-error-type

Conversation

@dmmulroy
Copy link
Copy Markdown

Fixes #6577.

What

Adds two new ambient TypeScript interfaces to types/defines/rpc.d.ts:

  • WorkersRpcError extends Error — base interface covering the three hint properties that the Workers runtime stamps onto any tunneled RPC exception:
    • retryable?: boolean — set when kj::Exception::Type::DISCONNECTED
    • overloaded?: boolean — set when kj::Exception::Type::OVERLOADED
    • remote?: boolean — set when the error originated on the remote side
  • DurableObjectError extends WorkersRpcError — adds the DO-only property:
    • durableObjectReset?: boolean — set when the actor was reset (the stub is broken and must be recreated)

Why

These properties have been stamped onto JS Error objects since #2202 (May 2024, re-landed as 37e4a9b in June 2024), are documented at Durable Objects → Error handling, and are widely used in practice — including by Cloudflare's own agents SDK, which has to reinvent the cast:

const typed = err as { retryable?: boolean; overloaded?: boolean };

Until now there has been no exported TypeScript type for them, so every consumer redefines their own interface. This PR closes that gap.

Design notes

Why two interfaces, not one. The four runtime properties fall into two natural tiers based on where they're set in src/workerd/jsg/util.c++:

  • retryable / overloaded / remote are applied in addAdditionalInfo() for any tunneled exception (service binding, WorkerEntrypoint, RpcTarget, Durable Object, Workflow).
  • durableObjectReset is only set when the incoming kj::Exception description starts with broken. — and every site that adds that prefix is actor-scoped (actor-cache.c++, actor-sqlite.c++, actor-state.c++, actor alarm/event timeout in global-scope.c++, actor constructor failure in worker.c++, actor eviction in server.c++, input-gate failure in io-context.h).

Splitting them lets callers of non-DO RPC (service bindings, Worker RPC) catch a typed WorkersRpcError without a misleading durableObjectReset field they'll never see, while DO callers still get a fully-typed DurableObjectError.

Why ?: boolean, not ?: true. The runtime only ever writes true and never writes false, so ?: true would be more accurate, but ?: boolean matches the shape already used in the wild (including in the agents SDK and the form the issue reporter suggested), and is less ceremonious for users who want to mock or construct these in tests.

Naming. WorkersRpcError mirrors the "Workers RPC" name used across the public docs and avoids colliding with the common JSON-RPC RpcError type in the ecosystem. DurableObjectError matches exactly what issue #6577 requests and what the developer docs call it.

Changes

File Change
types/defines/rpc.d.ts +51 — new WorkersRpcError + DurableObjectError interfaces with JSDoc
types/test/types/rpc.ts +38 — type-level tests asserting shape, inheritance, and that durableObjectReset is DO-only
types/generated-snapshot/{latest,experimental}/index.{d.ts,ts} +47 each — regenerated via just generate-types

Validation

  • just generate-types — snapshot regenerated cleanly
  • npx tsc --noEmit (types/test/types) — ✅ passes
  • just format — ✅ 80 files unchanged
  • pnpm exec eslint types/test/types/rpc.ts on the added block — ✅ no new errors (uses toExtend and not.toHaveProperty rather than the deprecated toMatchTypeOf)

Follow-ups (not in this PR)

  • The developer docs page currently only mentions retryable / overloaded / remote. With durableObjectReset now typed, it's worth a parallel PR against cloudflare/cloudflare-docs to document it alongside the others.
  • cloudflare/agents could drop its inline { retryable?: boolean; overloaded?: boolean } cast and use WorkersRpcError directly once this ships in @cloudflare/workers-types.

Workers RPC tunneled exceptions (from service bindings, WorkerEntrypoint,
RpcTarget, Durable Object stubs, or Workflows) can carry extra boolean
properties that hint at how the caller should handle the failure:

  - retryable          (Type::DISCONNECTED)
  - overloaded         (Type::OVERLOADED)
  - remote             (error originated on the remote side)
  - durableObjectReset (DO-specific: stub is broken, recreate it)

These are stamped onto the JS Error object by addAdditionalInfo() in
src/workerd/jsg/util.c++. Until now they were documented at
https://developers.cloudflare.com/durable-objects/best-practices/error-handling/
but had no exported TypeScript type, so every consumer (including
cloudflare/agents's isErrorRetryable) had to reinvent an inline cast like
"err as { retryable?: boolean; overloaded?: boolean }".

Expose them as two ambient interfaces in types/defines/rpc.d.ts:

  * WorkersRpcError  -- base, covers retryable/overloaded/remote. Applies
                        to any tunneled Workers RPC exception.
  * DurableObjectError extends WorkersRpcError -- adds durableObjectReset,
                        which is only set by actor-specific code paths
                        (actor-cache, actor-sqlite, input/output gates,
                        alarm handler, actor constructor, actor eviction).

Both are optional-property interfaces matching what the runtime actually
writes; neither property is ever set to false.

Regenerated types/generated-snapshot/{latest,experimental}/ and added
type-level tests in types/test/types/rpc.ts.

Fixes cloudflare#6577
@dmmulroy dmmulroy requested review from a team as code owners April 17, 2026 18:41
Copy link
Copy Markdown
Contributor

@petebacondarwin petebacondarwin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks reasonable and useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Missing type for Durable Object errors

2 participants