When a client disconnects mid-stream, `pipeNodeReadableToNodeResponse`
destroys the readable React is piping into. React sees its destination
close before the render ended and aborts with a generic `Error("The
destination stream closed early.")`, which `onError` has no way to
distinguish from a real render error, so it ends up in `onRequestError`
as a server render error.
The Web streams path doesn't have this problem: cancelling the readable
passes the `ResponseAborted` reason straight through to React. This does
the same for the Node path by aborting the pipeable with that reason as
soon as the passthrough is destroyed early, before React's own close
handler runs. Genuine render errors still go through untouched.
Fixes#96704
---------
Co-authored-by: Jude Gao <jude.gao@vercel.com>
As discussed we are removing the deprecated field from `revalidateTag`
and `revalidatePath` as they aren't going away anytime soon and the new
`expire` APIs will have slightly different semantics so not a 1-1 rename
with no arguments change anymore. We are also adding the `unstable_`
prefix for `expireTag`/`expirePath` while we iterate on them so it's
clear they will change.
---------
Co-authored-by: Zack Tanner <1939140+ztanner@users.noreply.github.com>
This adds `expireTag()` and `expirePath` APIs which are replacing
`revalidateTag` and `revalidatePath`. As such this also marks
`revalidatePath` and `revalidateTag` as deprecated and marked for
removal.
The arguments passed to these methods match `revalidateTag` and
`revalidatePath` with the exception that `expireTag` can receive
multiple tags now as separate arguments which matches our new
`unstable_cacheTag()` API.
We are wanting to update these APIs as `revalidateTag` naming has caused
some confusion as to when the affected items will be updated. The
underlying behavior of `expireTag` is to mark an entry as out of date
and for it to no longer be used so we are expiring it.
If you call `expirePath('/blog/first'`) the next time that item is
requested it is considered expired so the cache will not be used for it
and a fresh entry will be generated. Similarly for `expireTag('posts',
'blog')` the next time any cache with that tag is requested it's
respective cache will not be leveraged and new cache will be populated.
---------
Co-authored-by: Zack Tanner <1939140+ztanner@users.noreply.github.com>
Co-authored-by: Delba de Oliveira <32464864+delbaoliveira@users.noreply.github.com>
As we've learned in #70467, compilation times can be quite high in CI,
when testing HMR behaviour. The fetch logging HMR tests are frequently
failing. Increasing the `retry` timeout should mitigate the flakiness.
### What
- After adding a new API `onRequestError()` and a few fixes on `register()` for `instrumentation.js`, it's time to promote it as stable API.
- Add warning `"experimental.instrumentationHook is no longer needed to be configured in Next.js"` when you configure a `instrumentationHook` option in next.config.js
Related PRs
#67539, #67671, #67703, #67848, #67859, #67856, #67805, #68616, #68672, #68764, #68845#68976, #68983
Closes NDX-89
### What
Provide `revalidateReason` in the `errorContext` argument of
`onRequestError` API
#### API
```ts
revalidateReason?: 'on-demand' | 'stale' | undefined
```
### Why
With this property, developer is able to determine if current error is
attached to an ISR request.
* `stale` means it revalidated due to the cache is expired
* `on-demand` means it revalidated due to a user initiated revalidation,
e.g. using `res.revalidate` to revalidate certain path
### Misc
* We don't generate edge entry of instrumentation when there's no edge
routes but instrumentation is presented
Note: for PPR case we'll tackle it later with another PPR specific task,
since we need to provide the render is a postpone render or just normal
render
Closes NDX-23
### What
* Rename the `request.url` in onRequestError callback arg to
`request.path`
* Align `routeType: "middleware"` with others, only contain the resource
path in the `request.path`, stripped out request origin.
### Why
For non middleware case, the `req.url` in next-server is actual resource
path, which only contains the pathname and search but without request
origin. For middleware case, the origin is included in the `req.url`.
This might be a implementation detail, but for users, having request
origin here might not be critical and super helpful since they will know
the deployment as a global context for error tracking.
Hence we align the property to a variable that not holding request
origin, given a better naming `request.path`. The idea is from `:path`
request header, which represents the resource path, only containing
pathname and search. e.g. `/a/b?c=2`
x-ref:
https://greenbytes.de/tech/webdav/draft-ietf-httpbis-http2-09.html#HttpRequest
Closes NDX-54
### What
Since the API is getting more stablized with few past iteration and it's
still under the experimental flag, it's good to ship as a API along with
the `instrumentation.js`
### What
Add tests cases for dynamic routes and suspense page rendering case coverage for onRequestError.
Mostly for checking the `routePath` where we can display the proper original route path
Closes NDX-22
Closes NDX-79
### What
Provide `renderSource` for app router pages rendering errors in
instrumentation.js `onRequestError`.
Discussed with @gnoff that we refactored the error handlers a bit to
decouple from the Error render source since the handlers act differently
in different render phase.
### Why
This provides an easy way to determine wether the renderign error is
actually from SSR or RSC rendering. Since the RSC error is embedded in
the flight data and the final errors is only reported through React SSR
rendering.
Previously you can use the `digest` property sent to browser to
associate the actual error logged with your o11y provider, but it still
takes some effort, this would be the easy way to capture the original
source
Closes NDX-24
### What
Cover the Next.js internal errors are not captured by instrumentation
onRequestError API
Also skip deployment tests for onRequestError API due to the private env
flag `__NEXT_EXPERIMENTAL_INSTRUMENTATION` cannot be used in deployment
<!-- Closes NDX-33 -->
## What
This PR introduces a new API `onRequestError` in `instrumentation.js`
convention, which can help you track the errors thrown from pages and
routes on server side.
### API
```ts
type RequestInfo = {
url: string
method: string
headers: Record<string, string | string [] | undefined>
}
type ErrorContext = {
routerKind: 'Pages Router' | 'App Router'
routePath: string
routeType: 'render' | 'route' | 'middleware'
}
export function onRequestError(error: unknown, request: RequestInfo, errorContext: ErrorContext) {
}
```
This experimental feature is now scoped behind an experimental env var
`__NEXT_EXPERIMENTAL_INSTRUMENTATION` now. You need to enable to use it
before the feature is fully ready off from experimental.
## Why
The purpose is to provide a way to track the server errors from Next.js
much easier, especially when users're uing an o11y provider such as
sentry/datadog/newrelic etc. to monitor server side exceptions. There're
different runtime (Node.js or Edge) and different type of routes (App
Router pages/API routes, Pages Router pages/API routes, middleware) that
makes the error tracking story more complex. This API will be an
universal way to get all the errors.
The reason of providing the related arguments like request info and
error context is aimed to provide more insights about associated
request, also the context about Next.js framework itself, like which
feature is throwing the error.