denoland/deno · error · TypeError

ERR_INVALID_ARG_VALUE

ERR_INVALID_ARG_VALUE

Error message

The 'headers' argument is invalid. Received ${headers}

What it means

When headers are supplied as a flat array (e.g. to writeHead(status, headers) or http.request options), _storeHeader expects [name, value, name, value, ...] pairs. An odd-length flat array has an orphan element, so it throws ERR_INVALID_ARG_VALUE for the whole 'headers' argument rather than silently dropping or mispairing a header.

Source

Thrown at ext/node/polyfills/_http_outgoing.ts:956

      if (headers) {
        if (headers === this[kOutHeaders]) {
          // kOutHeaders format: { lowercase: [OriginalName, value] }
          // deno-lint-ignore guard-for-in
          for (const key in headers) {
            const entry = headers[key];
            this._storeHeaderEntry(state, entry[0], entry[1], false);
          }
        } else if (ArrayIsArray(headers)) {
          if (headers.length && ArrayIsArray(headers[0])) {
            // Array of arrays: [[name, value], ...]
            for (let i = 0; i < headers.length; i++) {
              const entry = headers[i];
              this._storeHeaderEntry(state, entry[0], entry[1], true);
            }
          } else {
            // Flat array: [name, value, name, value, ...]
            if (headers.length % 2 !== 0) {
              throw new ERR_INVALID_ARG_VALUE("headers", headers);
            }

            for (let n = 0; n < headers.length; n += 2) {
              this._storeHeaderEntry(
                state,
                headers[n],
                headers[n + 1],
                true,
              );
            }
          }
        } else {
          // Plain object: { name: value }
          const keys = ObjectKeys(headers);
          for (let i = 0; i < keys.length; i++) {
            const k = keys[i];
            this._storeHeaderEntry(state, k, headers[k], true);
          }

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Make the array even-length: every name must be immediately followed by its value.
  2. Prefer object form writeHead(200, { 'content-type': 'text/html' }) or nested pairs [['content-type','text/html']] which the same code path accepts unambiguously.
  3. Validate dynamic arrays before passing: assert headers.length % 2 === 0.

Example fix

// before
res.writeHead(200, ['Content-Type', 'text/html', 'X-Extra']); // odd length

// after
res.writeHead(200, { 'Content-Type': 'text/html' });
// or pairs: [['Content-Type', 'text/html'], ['X-Extra', 'value']]
Defensive patterns

Strategy: validation

Validate before calling

function toHeaderPairs(headers) {
  if (!Array.isArray(headers)) return headers;
  if (headers.length % 2 !== 0) {
    throw new Error(`headers array must be even-length [name, value, ...]; got ${headers.length}`);
  }
  return headers;
}

Type guard

function isFlatHeaderArray(h) {
  return Array.isArray(h) && !(h.length && Array.isArray(h[0]));
}
// even-length flat arrays and [[name, value]] pairs are both accepted by writeHead

Prevention

When it happens

Trigger: res.writeHead(200, ['Content-Type', 'text/html', 'X-Extra']) (3 elements); http.request({ headers: ['accept'] }); any code that builds a flat header array dynamically and loses or adds one element.

Common situations: Dynamically constructed header arrays where a push of a name without a value (or a value pushed as two entries) breaks pairing; migrating from object-form headers ({'x': 'y'}) to array-form and missing a member; typos in long header literals.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/435b86db6d5c53d3. Report an issue: GitHub.