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

  1. 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}.
  2. Check relay logs for state loss/restart; if the relay rewound its catalog revision, restart the bridge process so it resumes from initialRevision.
  3. Inspect the raw response with curl -X POST <relayUrl>/catalog/next to confirm the body shape and rule out proxies rewriting it.
  4. 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

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


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/63c1ee96a38adfca. Report an issue: GitHub.