ruvnet/ruflo · error · HttpFetchValidationError

INVALID_HEADERS

INVALID_HEADERS

Error message

headers must be an object

What it means

Thrown by the http_fetch handler when input.headers is present but not a plain object — it is null, an array, or a primitive. Headers must be a Record<string,string>; the check runs before validateHeaders iterates entries. The error carries code INVALID_HEADERS.

Source

Thrown at v3/@claude-flow/cli/src/mcp-tools/http-fetch-tools.ts:199

      status: 0,
      statusText: '',
      headers: {},
      body: '',
      bodyTruncated: false,
      bytesRead: 0,
      durationMs: Date.now() - startedAt,
      url,
      method,
      error: err.message,
      errorCode: err.code ?? 'VALIDATION_ERROR',
    };
  }

  let headers: Record<string, string>;
  try {
    const raw = (input.headers ?? {}) as Record<string, string>;
    if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
      throw new HttpFetchValidationError('headers must be an object', 'INVALID_HEADERS');
    }
    headers = validateHeaders(raw);
  } catch (e) {
    const err = e as HttpFetchValidationError;
    return {
      success: false,
      status: 0,
      statusText: '',
      headers: {},
      body: '',
      bodyTruncated: false,
      bytesRead: 0,
      durationMs: Date.now() - startedAt,
      url,
      method,
      error: err.message,
      errorCode: err.code ?? 'VALIDATION_ERROR',
    };

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Pass headers as a plain object { key: 'value' } or omit the field entirely.
  2. Convert header arrays/strings into an object before calling http_fetch.
  3. Use {} as the default, not null, when conditionally building headers.
  4. Type the headers parameter as Record<string,string> at the call site to catch this at compile time.

Example fix

// before
http_fetch({ url, headers: null })
// after
http_fetch({ url })  // omit when no headers are needed
Defensive patterns

Strategy: type-guard

Validate before calling

function normalizeHeaders(raw) {
  if (raw == null) return {};
  if (typeof raw !== 'object' || Array.isArray(raw)) {
    throw new Error('headers must be a plain object');
  }
  return raw;
}

Type guard

function isPlainHeaderObject(h: unknown): h is Record<string, unknown> {
  return typeof h === 'object' && h !== null && !Array.isArray(h);
}

Prevention

When it happens

Trigger: Passing headers as null, an array (e.g. [['a','b']]), a string, or a number. The guard `typeof raw !== 'object' || raw === null || Array.isArray(raw)` catches all three.

Common situations: Passing a header string like 'Authorization: Bearer x' instead of an object; sending a FormData or URLSearchParams instance that is object-like but not a plain record; defaulting headers to null when none are needed (omit the field instead).

Related errors


AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12). Data as JSON: /api/errors/6892141e45171e1a. Report an issue: GitHub.