diff --git a/.changeset/accept-header-not-acceptable.md b/.changeset/accept-header-not-acceptable.md new file mode 100644 index 00000000000..4b4b90a2bbb --- /dev/null +++ b/.changeset/accept-header-not-acceptable.md @@ -0,0 +1,5 @@ +--- +'@tanstack/start-server-core': patch +--- + +Return `406 Not Acceptable` instead of `500 Internal Server Error` when a page route receives a request whose `Accept` header excludes HTML. diff --git a/e2e/react-start/basic/tests/accept-header.spec.ts b/e2e/react-start/basic/tests/accept-header.spec.ts new file mode 100644 index 00000000000..b95c3b372dc --- /dev/null +++ b/e2e/react-start/basic/tests/accept-header.spec.ts @@ -0,0 +1,30 @@ +import { expect } from '@playwright/test' +import { test } from '@tanstack/router-e2e-utils' +import { isPrerender } from './utils/isPrerender' +import { isSpaMode } from './utils/isSpaMode' + +test.skip( + isSpaMode || isPrerender, + 'Accept negotiation only runs when the document is server-rendered', +) + +test.describe('Accept header negotiation', () => { + test('responds 406 when Accept excludes HTML', async ({ request }) => { + const response = await request.get('/', { + headers: { Accept: 'application/json' }, + }) + + expect(response.status()).toBe(406) + expect(await response.json()).toEqual({ + error: 'Only HTML requests are supported here', + }) + }) + + test('responds 200 when Accept allows HTML', async ({ request }) => { + const response = await request.get('/', { + headers: { Accept: 'text/html' }, + }) + + expect(response.status()).toBe(200) + }) +}) diff --git a/packages/start-server-core/src/createStartHandler.ts b/packages/start-server-core/src/createStartHandler.ts index c7b427bfb1f..a9dc49c88c9 100644 --- a/packages/start-server-core/src/createStartHandler.ts +++ b/packages/start-server-core/src/createStartHandler.ts @@ -653,7 +653,7 @@ export function createStartHandler( return normalizeSsrResponse( Response.json( { error: 'Only HTML requests are supported here' }, - { status: 500 }, + { status: 406 }, ), ) }