vercel/ai · error

Tool relay ${schema.name} failed with ${res.status}: ${body.

Error message

Tool relay ${schema.name} failed with ${res.status}: ${body.slice(0, 500)}

What it means

The in-sandbox MCP host-tool server relays each tool invocation to the host process over HTTP via TOOL_RELAY_URL. When the relay responds with a non-2xx status, the bridge turns it into an error containing the tool name, HTTP status, and the first 500 chars of the response body, which is then surfaced to the model as a tool error. This indicates the host-side relay endpoint rejected or failed to execute the tool call.

Source

Thrown at packages/harness-opencode/src/bridge/host-tool-mcp.ts:63

for (const schema of schemas) {
  const shape = toZodShape(schema.inputSchema);
  server.tool(
    schema.name,
    schema.description ?? '',
    shape,
    async (input: Record<string, unknown>) => {
      const requestId = crypto.randomUUID();
      try {
        const res = await fetch(relayUrl, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({ requestId, toolName: schema.name, input }),
        });
        if (!res.ok) {
          const body = await res.text();
          throw new Error(
            `Tool relay ${schema.name} failed with ${res.status}: ${body.slice(0, 500)}`,
          );
        }
        const data = (await res.json()) as { result?: unknown };
        return {
          content: [
            {
              type: 'text' as const,
              text: JSON.stringify(data.result ?? null),
            },
          ],
        };
      } catch (err) {
        return {
          content: [{ type: 'text' as const, text: `Error: ${String(err)}` }],
          isError: true,
        };
      }

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Check the response body in the error message for the relay's own error detail and fix the host-side tool implementation accordingly.
  2. Verify TOOL_RELAY_URL matches the host relay's actual address and port and that the relay process is still running.
  3. Retry the tool call; transient host restarts cause one-off 5xx responses.
  4. Ensure the sandbox can reach the host network (no firewall/network isolation blocking the relay).

Example fix

// before (host relay returning 500 because handler throws)
relay.post('/tool', async (req, res) => { await runTool(req.body); res.send(...) });
// after
relay.post('/tool', async (req, res) => {
  try { const result = await runTool(req.body); res.json({ result }); }
  catch (e) { console.error('tool failed', e); res.status(500).json({ error: String(e) }); }
});
Defensive patterns

Strategy: try-catch

Validate before calling

const relayOk = await fetch(process.env.TOOL_RELAY_URL, { method: 'HEAD' }).then(r => r.ok).catch(() => false);
if (!relayOk) throw new Error('Tool relay unreachable before session start');

Type guard

function isToolRelayHttpError(e: unknown): e is Error & { message: string } {
  return e instanceof Error && /^Tool relay .+ failed with \d{3}:/.test(e.message);
}

Try / catch

try {
  const result = await agent.run(...);
} catch (e) {
  if (isToolRelayHttpError(e)) {
    console.error('Relay status/body:', e.message);
    // restart host relay, then retry the turn
  } else throw e;
}

Prevention

When it happens

Trigger: Calling any bridged host tool from inside the OpenCode sandbox when the TOOL_RELAY_URL HTTP endpoint returns a non-OK status (400/404/500, etc.), e.g. the host relay process crashed, the URL points to the wrong port/path, or the host handler threw while executing the tool.

Common situations: Host process restarted or exited mid-session leaving the relay dead; misconfigured TOOL_RELAY_URL port; the host tool implementation itself raised an exception that the relay returned as a 500; auth/CORS proxy in front of the relay rejecting the POST.

Related errors


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