Skip to content

fix(fastify): treat a JSON content type with parameters as JSON in reply() - #17867

Merged
kamilmysliwiec merged 1 commit into
nestjs:masterfrom
fadiroot:fix/fastify-reply-content-type
Sep 24, 2026
Merged

kamilmysliwiec merged 1 commit into
nestjs:masterfrom
fadiroot:fix/fastify-reply-content-type

Conversation

@fadiroot

Copy link
Copy Markdown

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Other... Please describe:

What is the current behavior?

Issue Number: N/A

FastifyAdapter.reply() compares the Content-Type header with the exact string application/json. A JSON content type that carries parameters, such as application/json; charset=utf-8, is therefore treated as non-JSON when an error body is sent: the adapter logs

Content-Type doesn't match Reply body, you might need a custom ExceptionFilter for non-JSON responses

for a body that is JSON, and then overwrites the header with application/json, dropping the charset.

This is easy to hit because @Header() values are applied before pipes run, so a handler like

@Get(':id')
@Header('Content-Type', 'application/json; charset=utf-8')
find(@Param('id', ParseIntPipe) id: number) {}

logs the warning on every GET /abc.

The express adapter had the same check and was changed to startsWith('application/json') in 4f391c2; the fastify adapter was not updated, so the two adapters behave differently.

What is the new behavior?

reply() checks typeof contentType === 'string' && !contentType.startsWith('application/json'), matching the express adapter. Parameterised JSON content types are left alone; non-JSON content types are still replaced by application/json for error bodies.

Two unit tests cover both cases in fastify-adapter.spec.ts.

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

…ply()

reply() compared the Content-Type header with the exact string
"application/json", so a value such as "application/json; charset=utf-8"
was treated as a non-JSON content type: the adapter logged the
"Content-Type doesn't match Reply body" warning for a JSON body and then
overwrote the header, dropping the charset parameter.

Compare with startsWith("application/json") instead, which is what the
express adapter has done since the same check was fixed there.
@kamilmysliwiec
kamilmysliwiec merged commit 3e903a0 into nestjs:master Sep 24, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants