denoland/deno · error · TypeError

Invalid header: length must be 2, but is ${header.length}

Error message

Invalid header: length must be 2, but is ${header.length}

What it means

fillHeaders processes a HeadersInit given as an array of pairs; every entry must have length exactly 2 ([name, value]). It runs on the Request constructor's init.headers path (ext/fetch/23_request.js) and for EventSource initial headers, so malformed pairs surface from new Request(url, { headers: [...] }).

Source

Thrown at ext/fetch/20_headers.js:103

/**
 * @param {string} potentialValue
 * @returns {string}
 */
function normalizeHeaderValue(potentialValue) {
  return httpTrim(potentialValue);
}

/**
 * @param {Headers} headers
 * @param {HeadersInit} object
 */
function fillHeaders(headers, object) {
  if (ArrayIsArray(object)) {
    for (let i = 0; i < object.length; ++i) {
      const header = object[i];
      if (header.length !== 2) {
        throw new TypeError(
          `Invalid header: length must be 2, but is ${header.length}`,
        );
      }
      appendHeader(headers, header[0], header[1]);
    }
  } else {
    for (const key in object) {
      if (!ObjectHasOwn(object, key)) {
        continue;
      }
      appendHeader(headers, key, object[key]);
    }
  }
}

function checkForInvalidValueChars(value) {
  for (let i = 0; i < value.length; i++) {
    const c = StringPrototypeCharCodeAt(value, i);

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Emit exactly [name, value] pairs.
  2. Prefer the object form { 'content-type': 'text/plain' } when the data is not already pairs.

Example fix

// before
new Request(url, { headers: [['accept', 'text/html', 'utf-8']] });
// after
new Request(url, { headers: [['accept', 'text/html']] });
Defensive patterns

Strategy: type-guard

Validate before calling

if (Array.isArray(headersInit) && !headersInit.every((h) => Array.isArray(h) && h.length === 2)) {
  throw new Error('headers array must contain [name, value] pairs');
}
new Request(url, { headers: headersInit });

Type guard

function isHeaderPairs(v: unknown): v is [string, string][] {
  return Array.isArray(v) &&
    v.every((e) => Array.isArray(e) && e.length === 2);
}

Prevention

When it happens

Trigger: new Request(url, { headers: [['x']] }) or { headers: [['a', 'b', 'c']] } — each inner array must contain exactly a name and a value.

Common situations: Building header pairs dynamically and pushing wrong-shaped rows; splitting a raw header block into nested arrays with an extra field.

Related errors


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/3896444072d37167. Report an issue: GitHub.