vercel/ai · error · RelayRequestError

Host tool ${body.toolName} is not active in catalog revision

Error message

Host tool ${body.toolName} is not active in catalog revision ${state.revision}.

What it means

Even with a matching catalogRevision, the requested tool must exist in the relay's current tool list (state.tools, matched by exact name). If no tool with that name is registered, handleInvocation returns this 404 RelayRequestError. This guards against invoking tools the host never exposed or that were removed without a client-side revision mismatch.

Source

Thrown at packages/harness-acp/src/v1/bridge/host-tool-relay.ts:299

    !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 ` +
        `${state.revision}.`,
    });
  }

  const correlationToken = randomBytes(32).toString('hex');
  turn.registerCorrelationInvocation({
    token: correlationToken,
    serverName,
    toolName: tool.name,
    input: body.input,
    order: nextInvocationOrder(),
  });
  turn.emitToolCall({
    toolCallId: body.requestId,
    toolName: tool.name,

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Only invoke tool names exactly as listed in the current /catalog/next response (match case and spelling).
  2. Re-fetch the catalog after any updateCatalog call and rebuild the client's tool list before invoking.
  3. Handle 404 by listing available tools back to the model/agent so it can pick a valid tool.
  4. If the tool should exist, verify the host actually registered it in the tools array passed to startHostToolRelay / updateCatalog.

Example fix

// before
await invokeHostTool('file_search', input); // guessed name
// after
const catalog = await pollCatalog(revision);
if (!catalog.tools.some(t => t.name === 'file_search')) {
  throw new Error('file_search not offered by host; available: ' + catalog.tools.map(t => t.name).join(', '));
}
await invokeHostTool('file_search', input);
Defensive patterns

Strategy: type-guard

Validate before calling

function assertToolAvailable(tools: ReadonlyArray<{ name: string }>, toolName: string) {
  if (!tools.some(t => t.name === toolName)) {
    throw new Error(`Tool '${toolName}' is not registered. Available: ${tools.map(t => t.name).join(', ')}`);
  }
}

Type guard

function isToolInCatalog(tools: ReadonlyArray<{ readonly name: string }>, toolName: string): boolean {
  return tools.some(item => item.name === toolName);
}

Try / catch

const res = await postJson(invokeUrl, body);
if (res.status === 404 && /is not active in catalog revision/.test((await res.json()).error ?? '')) {
  // report available tools back to the agent/model so it can choose a valid one
}

Prevention

When it happens

Trigger: Invoking a toolName that is not in the host's registered tool set — typos, case mismatches, calling a tool removed by the most recent updateCatalog, or a client fabricating tool names not advertised in the catalog.

Common situations: Model hallucinating a tool name the host never registered; prompt/driver renaming tools between catalog fetch and invoke; tool removed in a newer catalog while revision coincidentally matched (e.g. client not tracking revision properly); custom adapters aliasing names differently.

Related errors


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