Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,7 @@ function verifyTokenInsecure(provided: string, expected: string): boolean {

`passThroughOnException()` is a fail-open mechanism that sends requests to your origin when your Worker throws an unhandled exception. While it can be useful during migration from an origin server, it hides bugs and makes debugging difficult. Use explicit `try...catch` blocks with structured error responses instead.


Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Suggested change

<TypeScriptExample filename="src/index.ts">

```ts
Expand Down
22 changes: 16 additions & 6 deletions src/content/docs/workers/observability/errors.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -336,16 +336,23 @@ Configure the [Wasm Coredump Service](https://github.com/cloudflare/wasm-coredum

## Go to origin on error

By using [`event.passThroughOnException`](/workers/runtime-apis/context/#passthroughonexception), a Workers application will forward requests to your origin if an exception is thrown during the Worker's execution. This allows you to add logging, tracking, or other features with Workers, without degrading your application's functionality.
By using [`passThroughOnException()`](/workers/runtime-apis/context/#passthroughonexception), a Workers application can forward requests to your origin if an exception is thrown during the Worker's execution. This allows you to add logging, tracking, or other features with Workers, without degrading your application's functionality.

`ctx.passThroughOnException()` forwards requests for unhandled exceptions in your Worker code, not for errors from the origin `fetch()`. When proxying requests to an origin, wrap `fetch(request)` in `try...catch` and return a `5xx` response on failure. If the origin `fetch()` throws after consuming the request body, `passThroughOnException()` cannot replay the body.

<Tabs> <TabItem label="Module Worker" icon="seti:javascript">

```js
export default {
async fetch(request, env, ctx) {
ctx.passThroughOnException();
// an error here will return the origin response, as if the Worker wasn't present

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

think we still need this comment?

return fetch(request);

try {
return await fetch(request);
} catch (error) {
console.error("Origin fetch failed", error);
return new Response("Bad Gateway", { status: 502 });
}
},
};
```
Expand All @@ -365,9 +372,12 @@ addEventListener("fetch", (event) => {
});

async function handleRequest(request) {
// An error here will return the origin response, as if the Worker wasn’t present.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Think we still need this comment?

// ...
return fetch(request);
try {
return await fetch(request);
} catch (error) {
console.error("Origin fetch failed", error);
return new Response("Bad Gateway", { status: 502 });
}
}
```

Expand Down
23 changes: 21 additions & 2 deletions src/content/docs/workers/runtime-apis/context.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,11 @@ export default {

:::caution[Reuse of body]

The Workers Runtime uses streaming for request and response bodies. It does not buffer the body. Hence, if an exception occurs after the body has been consumed, `passThroughOnException()` cannot send the body again.
The Workers runtime uses streaming for request and response bodies. It does not buffer the body. If an exception occurs after the body has been consumed, `passThroughOnException()` cannot send the body again.

If this causes issues, we recommend cloning the request body and handling exceptions in code. This will protect against uncaught code exceptions. However some exception times such as exceed CPU or memory limits will not be mitigated.
For a Worker that proxies requests to an origin, avoid relying on the runtime fallback when the origin `fetch()` fails. If the origin `fetch()` throws after consuming the request body, the fallback request may reach your origin without the original body and fail with an unrelated `4xx` error. Catch origin fetch errors and return a `5xx` response instead.

This protects against uncaught code exceptions. It does not mitigate failures such as exceeding CPU or memory limits.
:::

The `passThroughOnException` method allows a Worker to [fail open](https://community.microfocus.com/cyberres/b/sws-22/posts/security-fundamentals-part-1-fail-open-vs-fail-closed), and pass a request through to an origin server when a Worker throws an unhandled exception. This can be useful when using Workers as a layer in front of an existing service, allowing the service behind the Worker to handle any unexpected error cases that arise in your Worker.
Expand All @@ -260,3 +262,20 @@ export default {
},
};
```

If your Worker proxies to origin in the normal request path, catch errors from the origin fetch to avoid a second fetch with a consumed request body:

```js
export default {
async fetch(request, env, ctx) {
ctx.passThroughOnException();

try {
return await fetch(request);
} catch (error) {
console.error("Origin fetch failed", error);
return new Response("Bad Gateway", { status: 502 });
}
},
};
```