vercel/ai · error · Error
${readErrorMessage({ value, status: response.status })}
Error message
${readErrorMessage({ value, status: response.status })} What it means
In postRelay, when the host tool relay responds with a non-ok HTTP status, the error thrown carries the relay's own error message (from the JSON body's 'error' field) or falls back to 'Host tool relay returned HTTP <status>.'. This surfaces server-side failures of /invoke, /catalog/next, and /catalog/seen calls to the caller.
Source
Thrown at packages/harness-acp/src/v1/bridge/host-tool-mcp.ts:105
}
}
async function postRelay({
path,
body,
}: {
path: string;
body: Readonly<Record<string, unknown>>;
}): Promise<unknown> {
const response = await postHostToolRelay({
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,
}: {View on GitHub (pinned to 69428b1f8b)
Solutions
- Read the thrown message: it is the relay's own 'error' field, so fix the underlying relay-reported condition first.
- If the message is the generic 'Host tool relay returned HTTP <status>', check the relay logs for that status code.
- Verify AI_SDK_ACP_HOST_TOOL_RELAY_CREDENTIAL is current and AI_SDK_ACP_HOST_TOOL_RELAY_URL is correct.
- For invoke failures, confirm the tool still exists in the catalog file and that the bridge's catalogRevision is fresh (restart the bridge to resync).
- Confirm the relay service is healthy and reachable.
Example fix
// before: stale credential AI_SDK_ACP_HOST_TOOL_RELAY_CREDENTIAL=old-token // after AI_SDK_ACP_HOST_TOOL_RELAY_CREDENTIAL=<freshly issued relay token>
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight check before starting heavy work:
const res = await fetch(relayUrl + '/catalog/seen', { method: 'POST', headers: { authorization: relayCredential }, body: JSON.stringify({ revision: 1 }) });
if (!res.ok) throw new Error(`Relay pre-flight failed: HTTP ${res.status}`); Try / catch
try {
await postRelay({ path: '/invoke', body });
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
if (/HTTP 40[13]/.test(message)) {
// refresh AI_SDK_ACP_HOST_TOOL_RELAY_CREDENTIAL and retry once
} else {
// surface the relay's error message to the MCP caller
}
} Prevention
- Rotate and distribute the relay credential before expiry.
- Health-check the relay URL at startup.
- Keep the local catalog in sync so /invoke never sends stale catalogRevision.
- Log the thrown message verbatim - it already contains the relay's own error detail.
When it happens
Trigger: Any postHostToolRelay call (from hostToolServer invoke, watchCatalog poll, or onListTools) where the relay returns HTTP >= 400: invalid relay credential (401/403), unknown toolName or stale catalogRevision on /invoke (4xx), relay internal error (5xx), or body without an 'error' string field.
Common situations: Expired or rotated AI_SDK_ACP_HOST_TOOL_RELAY_CREDENTIAL; invoking a tool that was removed from the host catalog; sending a catalogRevision the relay no longer accepts; relay deployment down or crashing on request; wrong AI_SDK_ACP_HOST_TOOL_RELAY_URL pointing at a different service.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- Failed to fetch the response.
- The response body is empty.
- Cartesia realtime client secret request failed: ${response.s
- Google realtime auth token request failed: ${response.status
- Invalid host tool catalog poll response.
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/ed50eb40d1148903.
Report an issue: GitHub.