Skip to content

Commit c6d8c37

Browse files
authored
Fix server error logging and add onUnhandledError support (#6495)
1 parent 90cbe9a commit c6d8c37

File tree

29 files changed

+954
-487
lines changed

29 files changed

+954
-487
lines changed

.changeset/log-server-errors.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@remix-run/server-runtime": patch
3+
---
4+
5+
Ensure un-sanitized server errors are logged on the server during document requests

.changeset/on-unhandled-error.md

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
"@remix-run/server-runtime": minor
3+
---
4+
5+
Add optional `onUnhandledError` export for custom server-side error processing. This is a new optional export from your `entry.server.tsx` that will be called with any encountered error on the Remix server (loader, action, or render error):
6+
7+
```ts
8+
// entry.server.tsx
9+
export function onUnhandledError(
10+
error: unknown,
11+
{ request, params, context }: DataFunctionArgs
12+
): void {
13+
if (error instanceof Error) {
14+
sendErrorToBugReportingService(error);
15+
console.error(formatError(error));
16+
} else {
17+
let unknownError = new Error("Unknown Server Error");
18+
sendErrorToBugReportingService(unknownError);
19+
console.error(unknownError);
20+
}
21+
}
22+
```

docs/file-conventions/entry.server.md

+45-2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,53 @@ toc: false
55

66
# entry.server
77

8-
By default, Remix will handle generating the HTTP Response for you. If you want to customize this behavior, you can run `npx remix reveal` to generate a `app/entry.server.tsx` (or `.jsx`) that will take precedence. The `default` export of this module is a function that lets you create the response, including HTTP status, headers, and HTML, giving you full control over the way the markup is generated and sent to the client.
8+
By default, Remix will handle generating the HTTP Response for you. If you want to customize this behavior, you can run `npx remix reveal` to generate an `app/entry.server.tsx` (or `.jsx`) that will take precedence. The `default` export of this module is a function that lets you create the response, including HTTP status, headers, and HTML, giving you full control over the way the markup is generated and sent to the client.
99

1010
This module should render the markup for the current page using a `<RemixServer>` element with the `context` and `url` for the current request. This markup will (optionally) be re-hydrated once JavaScript loads in the browser using the [browser entry module][browser-entry-module].
1111

12-
You can also export an optional `handleDataRequest` function that will allow you to modify the response of a data request. These are the requests that do not render HTML, but rather return the loader and action data to the browser once client-side hydration has occurred.
12+
## `handleDataRequest`
13+
14+
You can export an optional `handleDataRequest` function that will allow you to modify the response of a data request. These are the requests that do not render HTML, but rather return the loader and action data to the browser once client-side hydration has occurred.
15+
16+
```tsx
17+
export function handleDataRequest(
18+
response: Response,
19+
{ request, params, context }: DataFunctionArgs
20+
) {
21+
response.headers.set("X-Custom-Header", "value");
22+
return response;
23+
}
24+
```
25+
26+
## `onUnhandledError`
27+
28+
By default, Remix will log encountered server-side errors to the console. If you'd like more control over the logging, or would like to also report these errors to an external service, then you can export an optional `onUnhandledError` function which will give you control (and will disable the built-in error logging).
29+
30+
```tsx
31+
export function onUnhandledError(
32+
error: unknown,
33+
{ request, params, context }: DataFunctionArgs
34+
) {
35+
sendErrorToErrorReportingService(error);
36+
console.error(formatErrorForJsonLogging(error));
37+
}
38+
```
39+
40+
### Streaming Rendering Errors
41+
42+
When you are streaming your HTML responses via [`renderToPipeableStream`][rendertopipeablestream] or [`renderToReadableStream`][rendertoreadablestream], your own `onUnhandledError` implementation will only handle errors encountered uring the initial shell render. If you encounter a rendering error during subsequent streamed rendering you will need handle these errors manually since the Remix server has already sent the Response by that point.
43+
44+
- For `renderToPipeableStream`, you can handle these errors in the `onError` callback function. You will need to toggle a boolean when the in `onShellReady` so you know if the error was a shell rendering error (and can be ignored) or an async rendering error (and must be handled).
45+
- For an exmaple, please see the default [`entry.server.tsx`][node-streaming-entry-server] for Node.
46+
- For `renderToReadableStream`, you can handle these errors in the `onError` callback function
47+
- For an example, please see the default [`entry.server.tsx`][cloudflare-streaming-entry-server] for Cloudflare
48+
49+
### Thrown Responses
50+
51+
Note that this does not handle thrown `Response` instances from your `loader`/`action` functions. The intention of this handler is to find bugs in your code which result in unexpected thrown errors. If you are detecting a scenario and throwing a 401/404/etc. `Response` in your `loader`/`action` then it's an expected flow that is handled by your code. If you also wish to log, or send those to an external service, that should be done at the time you throw the response.
1352

1453
[browser-entry-module]: ./entry.client
54+
[rendertopipeablestream]: https://react.dev/reference/react-dom/server/renderToPipeableStream
55+
[rendertoreadablestream]: https://react.dev/reference/react-dom/server/renderToReadableStream
56+
[node-streaming-entry-server]: https://github.com/remix-run/remix/blob/main/packages/remix-dev/config/defaults/node/entry.server.react-stream.tsx
57+
[cloudflare-streaming-entry-server]: https://github.com/remix-run/remix/blob/main/packages/remix-dev/config/defaults/cloudflare/entry.server.react-stream.tsx

0 commit comments

Comments
 (0)