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
- Pass headers as a plain object { key: 'value' } or omit the field entirely.
- Convert header arrays/strings into an object before calling http_fetch.
- Use {} as the default, not null, when conditionally building headers.
- 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
- Omit the headers field when none are needed instead of passing null.
- Default to {} when building headers conditionally.
- Type the parameter as Record<string,string>.
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
- INVALID_HEADER_VALUE
- INVALID_URL
- FORBIDDEN_HEADER
- candidate ${label} must ingest at least one vector
- records must be a non-empty array of {id?, vector, text?}
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/6892141e45171e1a.
Report an issue: GitHub.