types: add WorkersRpcError and DurableObjectError interfaces#6604
Open
dmmulroy wants to merge 1 commit intocloudflare:mainfrom
Open
types: add WorkersRpcError and DurableObjectError interfaces#6604dmmulroy wants to merge 1 commit intocloudflare:mainfrom
dmmulroy wants to merge 1 commit intocloudflare:mainfrom
Conversation
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
petebacondarwin
approved these changes
Apr 21, 2026
Contributor
petebacondarwin
left a comment
There was a problem hiding this comment.
This looks reasonable and useful.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 whenkj::Exception::Type::DISCONNECTEDoverloaded?: boolean— set whenkj::Exception::Type::OVERLOADEDremote?: boolean— set when the error originated on the remote sideDurableObjectError 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
agentsSDK, which has to reinvent the cast: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/remoteare applied inaddAdditionalInfo()for any tunneled exception (service binding,WorkerEntrypoint,RpcTarget, Durable Object, Workflow).durableObjectResetis only set when the incomingkj::Exceptiondescription starts withbroken.— and every site that adds that prefix is actor-scoped (actor-cache.c++,actor-sqlite.c++,actor-state.c++, actor alarm/event timeout inglobal-scope.c++, actor constructor failure inworker.c++, actor eviction inserver.c++, input-gate failure inio-context.h).Splitting them lets callers of non-DO RPC (service bindings, Worker RPC) catch a typed
WorkersRpcErrorwithout a misleadingdurableObjectResetfield they'll never see, while DO callers still get a fully-typedDurableObjectError.Why
?: boolean, not?: true. The runtime only ever writestrueand never writesfalse, so?: truewould be more accurate, but?: booleanmatches the shape already used in the wild (including in theagentsSDK and the form the issue reporter suggested), and is less ceremonious for users who want to mock or construct these in tests.Naming.
WorkersRpcErrormirrors the "Workers RPC" name used across the public docs and avoids colliding with the common JSON-RPCRpcErrortype in the ecosystem.DurableObjectErrormatches exactly what issue #6577 requests and what the developer docs call it.Changes
types/defines/rpc.d.tsWorkersRpcError+DurableObjectErrorinterfaces with JSDoctypes/test/types/rpc.tsdurableObjectResetis DO-onlytypes/generated-snapshot/{latest,experimental}/index.{d.ts,ts}just generate-typesValidation
just generate-types— snapshot regenerated cleanlynpx tsc --noEmit(types/test/types) — ✅ passesjust format— ✅ 80 files unchangedpnpm exec eslint types/test/types/rpc.tson the added block — ✅ no new errors (usestoExtendandnot.toHavePropertyrather than the deprecatedtoMatchTypeOf)Follow-ups (not in this PR)
retryable/overloaded/remote. WithdurableObjectResetnow typed, it's worth a parallel PR againstcloudflare/cloudflare-docsto document it alongside the others.cloudflare/agentscould drop its inline{ retryable?: boolean; overloaded?: boolean }cast and useWorkersRpcErrordirectly once this ships in@cloudflare/workers-types.