vercel/ai · error
Invalid host tool catalog.
Error message
Invalid host tool catalog.
What it means
Thrown by validateToolCatalog when the tool catalog data is not an array of valid tool entries. Each entry must be an object with a string 'name', optional string 'description', and optional object (non-array) 'inputSchema'. This runs both on the catalog file read at startup (readToolCatalog) and on every catalog update received from the relay during watchCatalog.
Source
Thrown at packages/harness-acp/src/v1/bridge/host-tool-mcp.ts:116
relayUrl,
relayCredential,
path,
body,
});
const { value } = response;
if (!response.ok) {
throw new Error(readErrorMessage({ value, status: response.status }));
}
return value;
}
function validateToolCatalog({
value,
}: {
value: unknown;
}): ReadonlyArray<HarnessV1BridgeToolWire> {
if (!Array.isArray(value) || !value.every(isTool)) {
throw new Error('Invalid host tool catalog.');
}
return value;
}
async function readToolCatalog({
path,
}: {
path: string;
}): Promise<ReadonlyArray<HarnessV1BridgeToolWire>> {
const text = await readFile(path, 'utf8');
const value = await new Response(text, {
headers: { 'content-type': 'application/json' },
}).json();
return validateToolCatalog({ value });
}
function isTool(value: unknown): value is HarnessV1BridgeToolWire {
return (View on GitHub (pinned to 69428b1f8b)
Solutions
- Open AI_SDK_ACP_HOST_TOOLS_FILE and validate it is a JSON array of objects each with a string 'name'.
- Fix offending entries: rename 'toolName'->'name', remove or convert array 'inputSchema' to a JSON Schema object, or delete the invalid entry.
- Validate the file against HarnessV1BridgeToolWire (name: string, description?: string, inputSchema?: object).
- If the error comes from a relay update, inspect the host's tool registration code to see why it emits an invalid tool entry.
Example fix
// before (tools file)
[{ "toolName": "read_file", "inputSchema": [] }]
// after
[{ "name": "read_file", "description": "Read a file", "inputSchema": { "type": "object", "properties": {} } }] Defensive patterns
Strategy: validation
Validate before calling
function isValidToolEntry(t) {
return (
t != null && typeof t === 'object' && !Array.isArray(t) &&
typeof t.name === 'string' &&
(t.description === undefined || typeof t.description === 'string') &&
(t.inputSchema === undefined || (typeof t.inputSchema === 'object' && t.inputSchema !== null && !Array.isArray(t.inputSchema)))
);
}
const tools = JSON.parse(fs.readFileSync(process.env.AI_SDK_ACP_HOST_TOOLS_FILE, 'utf8'));
if (!Array.isArray(tools) || !tools.every(isValidToolEntry)) throw new Error('tools file fails HarnessV1BridgeToolWire shape'); Type guard
function isHarnessToolWire(value: unknown): value is HarnessV1BridgeToolWire {
return (
value != null && typeof value === 'object' && !Array.isArray(value) &&
typeof (value as any).name === 'string' &&
((value as any).description === undefined || typeof (value as any).description === 'string') &&
((value as any).inputSchema === undefined || (typeof (value as any).inputSchema === 'object' && (value as any).inputSchema !== null && !Array.isArray((value as any).inputSchema)))
);
} Try / catch
let tools;
try {
tools = await readToolCatalog({ path: catalogPath });
} catch (error) {
throw new Error(`Host tools file ${catalogPath} is invalid: ${error instanceof Error ? error.message : String(error)}`);
} Prevention
- Validate the tools JSON file in CI against HarnessV1BridgeToolWire.
- Generate the tools file programmatically instead of hand-editing it.
- Never use arrays for inputSchema - it must be a JSON Schema object.
- Lint tool entries for the exact field names ('name', not 'toolName').
When it happens
Trigger: (1) The file at AI_SDK_ACP_HOST_TOOLS_FILE contains JSON that is not an array, or entries missing 'name', with a non-string name/description, or an array 'inputSchema'. (2) The relay's /catalog/next update carries a 'tools' field failing the same checks.
Common situations: Hand-edited tools file with a typo (e.g. 'inputSchema': [] or name misspelled as 'toolName'); JSON written as a single object instead of an array; a newer/older wire format where the schema field was renamed; relay host writing malformed catalog JSON.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Harness 'claude-code' requires a JSON schema for structured
- Invalid host tool relay request.
- Cline MCP server ${JSON.stringify(input.serverName)} must de
- 'HarnessAgent: `sandboxConfig.onBootstrap` and `sandboxConfi
- 'HarnessAgent: `sandboxConfig.workDir` must not be empty.'
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/748a05e3dac19f30.
Report an issue: GitHub.