Skip to content

Fastify integration captures 4xx errors raised before the reply status is set (e.g. empty JSON body) #24926

Description

@tobias-schnabel

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/nestjs

SDK Version

11.1.0

Framework Version

NestJS 12, @nestjs/platform-fastify 12, Fastify 5.12.5

Link to Sentry event

https://kpler.sentry.io/issues/7763870286/events/77524398057d4e309eeb9a3f443f4af0/?project=4511819824889856

Reproduction Example/SDK Setup

Sentry.init({
  integrations: defaults => [
    ...defaults.filter(integration => integration.name !== 'ProcessSession'),
    Sentry.httpIntegration({ sessions: false }),
  ],
});

No tracesSampleRate, no setupFastifyErrorHandler, no custom shouldHandleError.

Steps to Reproduce

  1. Run a NestJS app on FastifyAdapter (or a plain Fastify 5 app) with the SDK set up as above.
  2. Send a request with a JSON content type and an empty body: curl -X POST http://localhost:3000/ -H 'Content-Type: application/json'

Expected Result

The client gets a 400 and nothing is sent to Sentry, since the default shouldHandleError skips 4xx.

Actual Result

The client gets a 400, but Sentry receives an unhandled error:

FastifyError: Body cannot be empty when content-type is set to 'application/json'
mechanism: auto.function.fastify, handled: false

The same happens for an invalid JSON body (FST_ERR_CTP_INVALID_JSON_BODY).

Additional Context

Fastify runs onError hooks before it applies the error's status to the reply. For errors raised outside the route handler, such as body parsing, defaultShouldHandleError still reads reply.statusCode === 200, which it treats as "capture". #18418 fixed the same symptom upstream in Fastify 5.7.0, but only for route handler errors on the diagnostics channel path.

This started for us with v11, where fastifyIntegration registers the onError hook automatically (#23460). Before that, the hook was only added by setupFastifyErrorHandler, which NestJS apps don't call.

A fix is up in #24924: when reply.statusCode is still the default 200, the default shouldHandleError resolves the status the same way Fastify's setErrorStatusCode does.

Priority

React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it.

Activity

  1. linear-code commented on Oct 1, 2026

    @linear-code
  2. moved this to Waiting for: Product Owner in GitHub Issues with 👀 3on Oct 1, 2026
  3. self-assigned this
    on Oct 1, 2026
  4. nicohrubec commented on Oct 2, 2026

    @nicohrubec
    Member

    Hey, thanks for writing in. I'll take a look.

  5. moved this from Waiting for: Product Owner to No status in GitHub Issues with 👀 3on Oct 2, 2026
  6. added a commit that references this issue on Oct 2, 2026
    9c10641
  7. nicohrubec commented on Oct 2, 2026

    @nicohrubec
    Member

    Just merged the fix, will go out with the next release today.

  8. github-actions commented on Oct 2, 2026

    @github-actions
    Contributor

    A PR closing this issue has just been released 🚀

    This issue was referenced by PR #24924, which was included in the 11.3.0 release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions