GoogleChrome/lighthouse · error · Error

Invalid value: Argument 'extra-headers' must be a string

Error message

Invalid value: Argument 'extra-headers' must be a string

What it means

The --extra-headers flag accepts either a JSON object string (inline) or a path to a JSON file. coerceExtraHeaders first allows undefined and object types, then requires any remaining value to be a string (which is then parsed as JSON or read from a file path). This error fires when the value is a type other than undefined, object, or string — e.g., a number or boolean.

Source

Thrown at cli/cli-flags.js:447

function coerceLocale(value) {
  if (value === undefined) return;

  if (typeof value !== 'string') throw new Error(`Invalid value: Argument 'locale' must be a string`);
  return /** @type {LH.Locale} */ (value);
}

/**
 * `--extra-headers` comes in as a JSON string or a path to a JSON string, but the flag value
 * needs to be the parsed object. Load file (if necessary) and returns the parsed object.
 * @param {unknown} value
 * @return {LH.SharedFlagsSettings['extraHeaders']}
 */
function coerceExtraHeaders(value) {
  // TODO: this function does not actually verify the object type.
  if (value === undefined) return value;
  if (typeof value === 'object') return /** @type {LH.SharedFlagsSettings['extraHeaders']} */ (value);
  if (typeof value !== 'string') {
    throw new Error(`Invalid value: Argument 'extra-headers' must be a string`);
  }

  // (possibly) load and parse extra headers from JSON.
  if (!value.startsWith('{')) {
    // If not a JSON object, assume it's a path to a JSON file.
    return JSON.parse(fs.readFileSync(value, 'utf-8'));
  }
  return JSON.parse(value);
}

/**
 * Take yarg's unchecked object value and ensure it's proper throttling settings.
 * @param {unknown} value
 * @return {LH.ThrottlingSettings|undefined}
 */
function coerceThrottling(value) {
  if (value === undefined) return;

View on GitHub (pinned to 9515cd4e58)

Solutions

  1. Pass extra headers as an inline JSON string: --extra-headers='{"Authorization":"Bearer token"}'
  2. Pass a path to a JSON file: --extra-headers=./headers.json
  3. When using the programmatic API, pass the parsed object directly in flags: {extraHeaders: {Authorization: 'Bearer token'}}

Example fix

# before
lighthouse --extra-headers=12345 https://example.com
# after
lighthouse --extra-headers='{"X-Custom-Header":"value"}' https://example.com
Defensive patterns

Strategy: validation

Validate before calling

// Validate extra-headers before passing to Lighthouse
function validateExtraHeaders(value) {
  if (value === undefined) return;
  if (typeof value === 'object') return; // already parsed object
  if (typeof value !== 'string') {
    throw new Error('--extra-headers must be a JSON string or file path');
  }
  // Optionally pre-validate JSON
  if (value.startsWith('{')) JSON.parse(value);
}

Type guard

/** @param {unknown} v */
function isExtraHeadersValue(v) {
  return v === undefined || typeof v === 'object' || typeof v === 'string';
}

Prevention

When it happens

Trigger: Passing --extra-headers with a value that yargs resolves to neither undefined, an object, nor a string. For example, a numeric value or a boolean that bypasses yargs's own type handling and reaches the coerce function.

Common situations: Programmatic yargs usage passing a non-string/non-object value; unusual flag syntax causing type coercion issues; shell quoting edge cases that produce unexpected types.

Related errors


AI-assisted analysis of GoogleChrome/lighthouse@9515cd4e58 (2026-08-13). Data as JSON: /api/errors/f440b180961a66f2. Report an issue: GitHub.