Skip to content

HTTP/1.1 304 with Content-Length closes the connection #5900

Open

Description

@koal44

A bodyless 304 response with a nonzero Content-Length causes request() to fail with UND_ERR_RES_CONTENT_LENGTH_MISMATCH and closes the connection. Removing the header avoids the failure.

A server is allowed to send a 304 (Not Modified) response with a length describing what the 200 response would have been (see RFC 9110 §8.6, and RFC 9112 §6.3). So the 304 needs an exception from any body-length check.

Here's a failing unit test.

import assert from 'node:assert/strict';
import { createServer } from 'node:http';
import { test } from 'node:test';
import { Client } from 'undici';

test('304 with Content-Length', async t => {
  const server = createServer((req, res) => {
    res.writeHead(304, { 'content-length': '123', etag: '"foo"' });
    res.end();
  });
  await new Promise(resolve => server.listen(0, '127.0.0.1', resolve));
  const client = new Client(`http://127.0.0.1:${server.address().port}`);
  t.after(async () => { await client.destroy(); server.close(); });
  const { statusCode, body } = await client.request({
    path: '/', method: 'GET', headers: { 'if-none-match': '"foo"' },
  });
  assert.equal(statusCode, 304);
  assert.equal(await body.text(), '');
});
> node --test ./undici-304.test.mjs
...
Error [ResponseContentLengthMismatchError]: Response body length does not match content-length header

Activity

  1. metcoder95 commented on Sep 28, 2026

    @metcoder95
    Member

    Would you like to send a PR to fix it?

  2. hungateJoseph commented on Sep 28, 2026

    @hungateJoseph

    Looks like this was fixed on main the same day you filed it, by #5864. onHeadersComplete now drops the content-length for 204/304 (and HEAD) so it's never checked against the empty body. Your test passes for me on a checkout of main.

    It's just not released yet, v8.11.2 was cut the day before that merged. Should be good with the next release.

  3. koal44 commented on Oct 8, 2026

    @koal44
    Author

    Sorry for the slow follow-up. I've now reviewed #5864 and #5956, and tested the latter against our HTTP/1 transport and Fetch cache revalidation. Together, they resolve the 304 behavior I reported, including connection reuse.

    For context, I'm working on a browser app that uses Undici and recently got drawn into the whole Fetch subsystem. I'm currently using a patched version for a few issues I encountered along the way. When I feel more confident in the system, I'd like to contribute fixes and tests back to Undici.

    I do appreciate the invite to submit a PR though, and will likely take that route in the future.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions