vercel/ai · error · RunError
CODE_MODE_HOST_TOOL_ERROR
CODE_MODE_HOST_TOOL_ERROR
Error message
Host tool failed.
What it means
When a host tool invoked from code-mode sandbox code throws an error that is neither a CodeModeError, a RunError, nor the internal HostFunctionInterruptSignal, invokeCodeModeTool replaces it with a generic RunError('Host tool failed.', 'CODE_MODE_HOST_TOOL_ERROR'). This avoids leaking arbitrary tool implementation errors (which may contain sensitive details) into the sandbox, at the cost of hiding the original message.
Source
Thrown at packages/code-mode/src/run-code-mode.ts:341
...(codeModeInterrupt === undefined ? {} : { codeModeInterrupt }),
skipApproval,
});
if (outcome.type === 'interrupted') {
return context.interrupt(outcome.payload);
}
return fromJsonPayload(outcome.valueJson);
} catch (error) {
if (error instanceof CodeModeError) {
codeModeErrors.push(error);
throw new RunError(error.message, error.code, error.details);
}
if (
RunError.isInstance(error) ||
(error instanceof Error && error.name === 'HostFunctionInterruptSignal')
) {
throw error;
}
throw new RunError('Host tool failed.', 'CODE_MODE_HOST_TOOL_ERROR');
}
}
function assertInterruptPayload(value: unknown): CodeModeInterruptPayload {
if (
typeof value !== 'object' ||
value === null ||
Array.isArray(value) ||
typeof (value as { kind?: unknown }).kind !== 'string'
) {
throw new CodeModeProtocolError(
'Code mode interruption payload is malformed.',
);
}
return value as CodeModeInterruptPayload;
}
function toRunLimits(View on GitHub (pinned to 69428b1f8b)
Solutions
- Check the tool's own logs/server-side for the underlying exception — the original message is intentionally not forwarded to the sandbox.
- Make the tool catch its own errors and return a structured error value (or throw a CodeModeError with details) instead of a raw Error.
- Add retry/error handling inside the tool execute function for transient failures like network errors.
Example fix
// before
execute: async input => { const res = await fetch(url); return await res.json(); } // raw throw -> 'Host tool failed.'
// after
execute: async input => {
try {
const res = await fetch(url);
return await res.json();
} catch (e) {
return { error: 'fetch_failed', detail: String(e) };
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// Harden tools so they never throw raw errors:
const safeTools = Object.fromEntries(Object.entries(tools).map(([name, tool]) => [name, wrapTool(tool)]));
// wrapTool catches errors and returns { error: string } instead of throwing. Try / catch
try {
await runCodeMode({ js, tools });
} catch (error) {
if (RunError.isInstance(error) && error.code === 'CODE_MODE_HOST_TOOL_ERROR') {
// check the tool's own logs for the real cause
}
throw error;
} Prevention
- Wrap every tool execute with try/catch and return structured error values.
- Add retries inside tools for transient network failures.
- Monitor tool implementations for unhandled exceptions; the sandbox will only show the generic message.
When it happens
Trigger: A tool's execute function throws a plain Error (network failure, unhandled exception, assertion) during a code-mode run; the error does not carry a code-mode error class so it is anonymized.
Common situations: Tools calling external HTTP APIs that go down; tool implementations with bugs that throw raw Errors; SDK version drift where a tool throws a new error type not recognized by the bridge.
Related errors
- error.message
- CODE_MODE_TOOL_ERROR
- Invalid argument for parameter batch: batch must be a suppor
- Sandbox session is not available
- Sandbox session is not available
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/851c245d06d4f9dd.
Report an issue: GitHub.