vercel/ai · error · Error
Invalid host tool catalog poll response.
Error message
Invalid host tool catalog poll response.
What it means
Thrown by watchCatalog in host-tool-mcp.ts when a long-poll response from the host tool relay endpoint (/catalog/next) is malformed: the body is not an object, lacks a safe-integer 'revision', or reports a revision older than the one already held. The bridge validates every poll response to guarantee catalog synchronization only ever moves forward with well-formed data. A closed signal ({closed:true}) is handled separately and does not throw.
Source
Thrown at packages/harness-acp/src/v1/bridge/host-tool-mcp.ts:80
initialRevision: number;
updateCatalog: (options: {
revision: number;
tools: ReadonlyArray<HarnessV1BridgeToolWire>;
}) => Promise<void>;
}): Promise<void> {
let revision = initialRevision;
for (;;) {
const value = await postRelay({
path: '/catalog/next',
body: { afterRevision: revision },
});
if (isRecord(value) && value.closed === true) return;
if (
!isRecord(value) ||
!Number.isSafeInteger(value.revision) ||
(value.revision as number) < revision
) {
throw new Error('Invalid host tool catalog poll response.');
}
const nextRevision = value.revision as number;
if (nextRevision === revision) continue;
const nextTools = validateToolCatalog({ value: value.tools });
await updateCatalog({ revision: nextRevision, tools: nextTools });
revision = nextRevision;
}
}
async function postRelay({
path,
body,
}: {
path: string;
body: Readonly<Record<string, unknown>>;
}): Promise<unknown> {
const response = await postHostToolRelay({
relayUrl,View on GitHub (pinned to 69428b1f8b)
Solutions
- Verify the relay at AI_SDK_ACP_HOST_TOOL_RELAY_URL implements the /catalog/next long-poll contract returning {revision: <safe integer>, tools: [...]} or {closed: true}.
- Check relay logs for state loss/restart; if the relay rewound its catalog revision, restart the bridge process so it resumes from initialRevision.
- Inspect the raw response with curl -X POST <relayUrl>/catalog/next to confirm the body shape and rule out proxies rewriting it.
- Ensure bridge and relay versions match (same AI SDK release line) so the wire format agrees.
Example fix
// before: relay returns { rev: 3, tools: [...] } (legacy field name)
// after: relay returns the expected shape
{ "revision": 3, "tools": [ { "name": "read_file", "inputSchema": {} } ] } Defensive patterns
Strategy: validation
Validate before calling
function isValidCatalogPoll(value) {
return (
value != null &&
typeof value === 'object' &&
!Array.isArray(value) &&
Number.isSafeInteger(value.revision)
);
}
// wrap the poll: only proceed when isValidCatalogPoll(body) && body.revision >= currentRevision Type guard
function isCatalogPollResponse(value: unknown): value is { revision: number; tools: unknown[] } {
return (
value != null && typeof value === 'object' && !Array.isArray(value) &&
Number.isSafeInteger((value as any).revision)
);
} Try / catch
try {
await watchCatalog({ initialRevision: 1, updateCatalog });
} catch (error) {
process.stderr.write(`catalog sync failed: ${error instanceof Error ? error.message : String(error)}\n`);
process.exitCode = 1; // restart the bridge to resync from initialRevision
} Prevention
- Run relay and bridge from the same release so the /catalog/next wire format matches.
- Add a contract test asserting the relay's /catalog/next response shape.
- Avoid proxies that rewrite JSON bodies on internal endpoints.
- If the relay restarts and revisions rewind, restart the bridge too.
When it happens
Trigger: Calling watchCatalog (indirectly, via the bridge startup at host-tool-mcp.ts:45) when the relay's /catalog/next response body is: (1) not a JSON object (array, string, null), (2) missing 'revision' or 'revision' is a float/NaN/non-number, or (3) 'revision' is lower than the current local revision (relay restarted or rewound its catalog).
Common situations: Running a mismatched or older relay server that returns a legacy response shape; a proxy/gateway stripping or rewriting the JSON body; a relay that lost state and restarted at revision 0/1 while the bridge is already past that revision; a load balancer serving an error page with HTTP 200.
Related errors
- Invalid host tool relay response.
- ${readErrorMessage({ value, status: response.status })}
- Invalid host tool catalog poll request.
- Invalid host tool catalog acknowledgment.
- Invalid host tool relay request.
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/63c1ee96a38adfca.
Report an issue: GitHub.