Error handling
Review how to handle errors (exceptions) generated by both your own Durable Object code as well as exceptions thrown by Durable Objects’ infrastructure (such as overloads or network errors).
How exceptions are thrown
There are three ways in which a Durable Object can throw an exception:
- From the code within the
fetch()
handler defined on your Durable Object class. The resulting exception will have a.remote
property set toTrue
in this case. - From code within the
constructor
method defined on your Durable Object class. The resulting exception will have a.remote
property set toTrue
in this case. - Generated by Durable Object’s infrastructure when you are sending too many requests to a single Durable Object, or when too many requests are queued due to slow or excessive I/O (external API calls or storage operations) within an individual Durable Object.
Refer to Troubleshooting to review the types of errors returned by a Durable Object and/or Durable Objects infrastructure and how to prevent them.
Understanding stubs
A Durable Object stub is a client Object used to send requests to a remote Durable Object. To learn more about how to make requests to a Durable Object, refer to Create Durable Objects stubs and Access a Durable Objects from a Worker.
Example
Any uncaught exceptions thrown by your code within a Durable Object’s fetch()
handler or constructor
method will be propagated to the caller’s fetch()
call:
export interface Env { ErrorThrowingObject: DurableObjectNamespace;
}
export default { async fetch( req: Request, env: Env, ctx: ExecutionContext ): Promise<Response> { // Any uncaught exceptions thrown by the Durable Object’s fetch() // handler will be propagated to the caller’s fetch() promise. // // If an uncaught exception is thrown by the Durable Object’s fetch() // handler, then the exception propagated to the caller’s fetch() // promise will include a .remote property, which will be set to True. // // This also includes uncaught exceptions in the Durable Object's // constructor, which will also set the .remote property to True on the // thrown exception. try { let userId = new URL(req.url).searchParams.get("userId") || ""; const id = env.ErrorThrowingObject.idFromName(userId); const doStub = env.ErrorThrowingObject.get(id); const resp = await doStub.fetch("http://your-do/");
return Response.json(resp); } catch (e: any) { // Exceptions caught here will have the .remote property if they were // thrown by the code in your Durable Object's fetch() handler if (e.remote) { // The exception was raised from code in your Durable Object's fetch handler }
// If the remote property is not present, then the error is likely to // indicate that your Worker could not reach the Durable Object itself, // representing a potential transient error (or overload) of your // Durable Object. Under most conditions, you should attempt to retry // 1-2 times before failing. return new Response("server error", { status: 500 }); } },
};
export class ErrorThrowingObject implements DurableObject { constructor(state: DurableObjectState, env: Env) { // Any exceptions that are raised in your constructor will also set the // .remote property to True throw "no good"; }
async fetch(req: Request) { // Generate an uncaught exception // A .remote property will be added to the exception propagated to the caller // and will be set to True throw new Error("example error");
// We never reach this return Response.json({}); }
}
When the exception is not generated from your own code and instead from Durable Object’s infrastructure, the .remote
property will not be present on the exception propagated to the caller’s fetch()
call:
try { let userId = new URL(req.url).searchParams.get("userId") || ""; const id = env.ErrorThrowingObject.idFromName(userId); const doStub = env.ErrorThrowingObject.get(id); const resp = await doStub.fetch("http://your-do/");
return Response.json(resp);
} catch (e: any) { // The .remote property would NOT be populated in this case if (e.remote) { // Code here will not be called }
return new Response("server error", { status: 500 });
}
When the .remote
property does not exist on the error, it is recommended that you retry the call to your Durable Object(s) as the error is more likely to be transient.