vercel/ai · warning · RelayRequestError
Unknown host tool relay endpoint.
Error message
Unknown host tool relay endpoint.
What it means
handleRequest rejects any HTTP request whose method is not POST with this 404 RelayRequestError. The relay only serves POST endpoints (/catalog/next, /catalog/seen, /invoke), so GET/PUT/DELETE requests to any path — including valid paths — are treated as unknown endpoints. It is surfaced to the client as a 404 JSON body with this message.
Source
Thrown at packages/harness-acp/src/v1/bridge/host-tool-relay.ts:161
}
async function handleRequest({
request,
credential,
state,
serverName,
turn,
nextInvocationOrder,
}: {
request: IncomingMessage;
credential: string;
state: CatalogState;
serverName: string;
turn: HostToolRelayTurn | undefined;
nextInvocationOrder: () => number;
}): Promise<unknown> {
if (request.method !== 'POST') {
throw new RelayRequestError({
status: 404,
message: 'Unknown host tool relay endpoint.',
});
}
if (
!credentialsMatch({
expected: credential,
actual: request.headers.authorization,
})
) {
throw new RelayRequestError({
status: 401,
message: 'Invalid host tool relay credential.',
});
}
const body = await readJSONBody({ request });
if (request.url === '/catalog/next') {
return handleCatalogNext({ body, state });View on GitHub (pinned to 69428b1f8b)
Solutions
- Send requests with method POST and a JSON body.
- Verify the client library call you use issues POST (e.g. fetch with { method: 'POST' }).
- Exclude the relay URL from GET-based health checks or add a dedicated POST-aware probe.
- Check the exact request.url you are hitting; the relay only serves /catalog/next, /catalog/seen, and /invoke.
Example fix
// before
const res = await fetch(relayUrl); // GET
// after
const res = await fetch(relayUrl, {
method: 'POST',
headers: { authorization: `Bearer ${credential}`, 'content-type': 'application/json' },
body: JSON.stringify({ requestId, toolName, input, catalogRevision }),
}); Defensive patterns
Strategy: validation
Validate before calling
function assertPost(url: string, init: RequestInit) {
if ((init.method ?? 'GET').toUpperCase() !== 'POST') {
throw new Error(`Host tool relay requires POST, got ${init.method ?? 'GET'} for ${url}`);
}
} Try / catch
try {
const res = await fetch(relay.url, { method: 'POST', ... });
if (!res.ok) {
const { error } = await res.json();
throw new Error(`${res.status}: ${error}`);
}
} catch (error) {
if (error instanceof Error && error.message.includes('Unknown host tool relay endpoint')) {
// fix HTTP method to POST and retry once
}
} Prevention
- Never open the relay URL directly in a browser or with curl without -X POST.
- Exclude relay endpoints from GET-based health checks.
- Centralize relay HTTP calls in one helper that always sets method: 'POST'.
When it happens
Trigger: Sending GET /invoke (e.g. opening the URL in a browser or curl without -X POST), a health-check probe hitting the relay URL with GET, or a misconfigured HTTP client using the wrong method against any relay path.
Common situations: Manually testing the relay URL in a browser; load balancer or health checks using GET on the MCP API handler route; SDK code or scripts using the wrong HTTP verb; proxying that strips or rewrites POST to GET on redirects.
Related errors
- Invalid host tool relay credential.
- ${readErrorMessage({ value, status: response.status })}
- A host tool relay turn is already active.
- Invalid host tool catalog poll request.
- Invalid host tool catalog acknowledgment.
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/5ac9573f8d749106.
Report an issue: GitHub.