denoland/deno · error · TypeError

ERR_INVALID_ARG_VALUE

ERR_INVALID_ARG_VALUE

Error message

The property 'headers[http2.neverIndex]' is invalid. Received ${neverIndex}

What it means

Response headers may carry a list of header names that must never be indexed in the HPACK dynamic table, attached with the http2.sensitiveHeaders symbol. validatePreparedResponseHeaders checks that headers[kSensitiveHeaders], if defined, is an Array; any other type throws ERR_INVALID_ARG_VALUE naming 'headers[http2.neverIndex]'.

Source

Thrown at ext/node/polyfills/http2.ts:2785

  validatePreparedResponseHeaders(headers, statusCode);

  return { headers, statusCode };
}

function validatePreparedResponseHeaders(headers, statusCode) {
  // This is intentionally stricter than the HTTP/1 implementation, which
  // allows values between 100 and 999 (inclusive) in order to allow for
  // backwards compatibility with non-spec compliant code. With HTTP/2,
  // we have the opportunity to start fresh with stricter spec compliance.
  // This will have an impact on the compatibility layer for anyone using
  // non-standard, non-compliant status codes.
  if (statusCode < 200 || statusCode > 599) {
    throw new ERR_HTTP2_STATUS_INVALID(statusCode);
  }

  const neverIndex = headers[kSensitiveHeaders];
  if (neverIndex !== undefined && !ArrayIsArray(neverIndex)) {
    throw new ERR_INVALID_ARG_VALUE("headers[http2.neverIndex]", neverIndex);
  }
}

function tryClose(fd) {
  fs.close(fd, (err) => {
    if (err) throw err;
  });
}

function processRespondWithFD(
  self,
  fd,
  headers,
  offset = 0,
  length = -1,
  streamOptions = 0,
) {
  const state = self[kState];

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Always pass an array of header names: [http2.sensitiveHeaders]: ['authorization']
  2. Normalize string input to an array in helper code: names = Array.isArray(x) ? x : [x]
  3. Leave the symbol off entirely when nothing is sensitive — undefined is allowed

Example fix

// before
stream.respond({
  ':status': 200,
  [http2.sensitiveHeaders]: 'set-cookie', // string → throws
});

// after
stream.respond({
  ':status': 200,
  [http2.sensitiveHeaders]: ['set-cookie'], // array of names
});
Defensive patterns

Strategy: validation

Validate before calling

const sensitive = rawSensitive === undefined
  ? undefined
  : Array.isArray(rawSensitive) ? rawSensitive : [rawSensitive];
stream.respond({ ':status': 200, [http2.sensitiveHeaders]: sensitive });

Type guard

const isSensitiveHeadersList = (v: unknown): v is string[] =>
  v === undefined || (Array.isArray(v) && v.every((n) => typeof n === 'string'));

Prevention

When it happens

Trigger: stream.respond({ ':status': 200, [http2.sensitiveHeaders]: 'authorization' }) — a bare string instead of an array; passing an object/Map of names; copy-paste from docs that dropped the array brackets.

Common situations: Marking Set-Cookie or Authorization as sensitive with a single name string because there is only one header; helpers that accept both a string and an array and forward whichever they got.

Related errors


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