vercel/ai · warning · RelayRequestError
Invalid host tool relay request.
Error message
Invalid host tool relay request.
What it means
A valid /invoke body must be an object with string requestId, string toolName, a record-valued input, and a safe-integer catalogRevision. If any of these is missing or of the wrong type, handleInvocation throws this 400 RelayRequestError. This is the structural schema check, applied after the active-turn check and before revision/tool checks.
Source
Thrown at packages/harness-acp/src/v1/bridge/host-tool-relay.ts:284
}): Promise<{
output: unknown;
isError?: boolean;
correlationToken: string;
}> {
if (turn == null) {
throw new RelayRequestError({
status: 409,
message: 'No ACP prompt turn is active.',
});
}
if (
!isRecord(body) ||
typeof body.requestId !== 'string' ||
typeof body.toolName !== 'string' ||
!isRecord(body.input) ||
!Number.isSafeInteger(body.catalogRevision)
) {
throw new RelayRequestError({
status: 400,
message: 'Invalid host tool relay request.',
});
}
if (body.catalogRevision !== state.revision) {
throw new RelayRequestError({
status: 409,
message:
`Host tool ${body.toolName} was invoked from stale catalog revision ` +
`${body.catalogRevision}; the active revision is ${state.revision}.`,
});
}
const tool = state.tools.find(item => item.name === body.toolName);
if (tool == null) {
throw new RelayRequestError({
status: 404,
message:
`Host tool ${body.toolName} is not active in catalog revision ` +View on GitHub (pinned to 69428b1f8b)
Solutions
- Send exactly { requestId: string, toolName: string, input: object, catalogRevision: safe integer }.
- Validate the payload client-side before POSTing (types + Number.isSafeInteger on catalogRevision).
- Ensure input is a JSON object (not an array or scalar) — serialize tool arguments as a record.
- If using a wrapper library, update it to match the current relay wire schema.
Example fix
// before
body: JSON.stringify({ id: 123, tool: name, args: input })
// after
body: JSON.stringify({
requestId: String(id),
toolName: name,
input,
catalogRevision: currentRevision,
}); Defensive patterns
Strategy: validation
Validate before calling
function isValidInvokeBody(body: unknown): body is {
requestId: string; toolName: string;
input: Record<string, unknown>; catalogRevision: number;
} {
return body != null && typeof body === 'object' && !Array.isArray(body) &&
typeof (body as any).requestId === 'string' &&
typeof (body as any).toolName === 'string' &&
(body as any).input != null && typeof (body as any).input === 'object' && !Array.isArray((body as any).input) &&
Number.isSafeInteger((body as any).catalogRevision);
} Type guard
function isRecord(value: unknown): value is Readonly<Record<string, unknown>> {
return value != null && typeof value === 'object' && !Array.isArray(value);
} Prevention
- Mirror the exact wire schema: requestId, toolName, input, catalogRevision.
- Ensure tool inputs serialize as JSON objects, not arrays or scalars.
- Send catalogRevision as a number, never a string.
- Add a client-side schema assertion unit test for the invoke payload.
When it happens
Trigger: POSTing /invoke with a missing input object, numeric or non-string requestId/toolName, a missing or non-integer catalogRevision, malformed JSON that parses to a non-object, or fields renamed in a custom client.
Common situations: Hand-written MCP-to-relay adapters with the wrong payload shape; JSON.stringify dropping undefined fields; catalogRevision sent as a string; frameworks auto-serializing inputs that contain arrays at the top level (rejected by isRecord).
Related errors
- Invalid host tool catalog poll request.
- Invalid host tool catalog acknowledgment.
- Invalid host tool catalog poll response.
- Invalid host tool catalog.
- Invalid host tool relay response.
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/7fb25220db32bc8e.
Report an issue: GitHub.