toolErrors.ts
utils/toolErrors.ts
133
Lines
4012
Bytes
3
Exports
3
Imports
10
Keywords
What this is
This page documents one file from the repository and includes its full source so you can read it without leaving the docs site.
Beginner explanation
This file is one piece of the larger system. Its name, directory, imports, and exports show where it fits. Start by reading the exports and related files first.
How it is used
Start from the exports list and related files. Those are the easiest clues for where this file fits into the system.
Expert explanation
Architecturally, this file intersects with tool-system. It contains 133 lines, 3 detected imports, and 3 detected exports.
Important relationships
Detected exports
formatErrorgetErrorPartsformatZodValidationError
Keywords
messageparamlengthreceivederrorpartspartsfullmessagepathexpectedcode
Detected imports
zod/v4./errors.js./messages.js
Source notes
This page embeds the full file contents. Small or leaf files are still indexed honestly instead of being over-explained.
Full source
import type { ZodError } from 'zod/v4'
import { AbortError, ShellError } from './errors.js'
import { INTERRUPT_MESSAGE_FOR_TOOL_USE } from './messages.js'
export function formatError(error: unknown): string {
if (error instanceof AbortError) {
return error.message || INTERRUPT_MESSAGE_FOR_TOOL_USE
}
if (!(error instanceof Error)) {
return String(error)
}
const parts = getErrorParts(error)
const fullMessage =
parts.filter(Boolean).join('\n').trim() || 'Command failed with no output'
if (fullMessage.length <= 10000) {
return fullMessage
}
const halfLength = 5000
const start = fullMessage.slice(0, halfLength)
const end = fullMessage.slice(-halfLength)
return `${start}\n\n... [${fullMessage.length - 10000} characters truncated] ...\n\n${end}`
}
export function getErrorParts(error: Error): string[] {
if (error instanceof ShellError) {
return [
`Exit code ${error.code}`,
error.interrupted ? INTERRUPT_MESSAGE_FOR_TOOL_USE : '',
error.stderr,
error.stdout,
]
}
const parts = [error.message]
if ('stderr' in error && typeof error.stderr === 'string') {
parts.push(error.stderr)
}
if ('stdout' in error && typeof error.stdout === 'string') {
parts.push(error.stdout)
}
return parts
}
/**
* Formats a Zod validation path into a readable string
* e.g., ['todos', 0, 'activeForm'] => 'todos[0].activeForm'
*/
function formatValidationPath(path: PropertyKey[]): string {
if (path.length === 0) return ''
return path.reduce((acc, segment, index) => {
const segmentStr = String(segment)
if (typeof segment === 'number') {
return `${String(acc)}[${segmentStr}]`
}
return index === 0 ? segmentStr : `${String(acc)}.${segmentStr}`
}, '') as string
}
/**
* Converts Zod validation errors into a human-readable and LLM friendly error message
*
* @param toolName The name of the tool that failed validation
* @param error The Zod error object
* @returns A formatted error message string
*/
export function formatZodValidationError(
toolName: string,
error: ZodError,
): string {
const missingParams = error.issues
.filter(
err =>
err.code === 'invalid_type' &&
err.message.includes('received undefined'),
)
.map(err => formatValidationPath(err.path))
const unexpectedParams = error.issues
.filter(err => err.code === 'unrecognized_keys')
.flatMap(err => err.keys)
const typeMismatchParams = error.issues
.filter(
err =>
err.code === 'invalid_type' &&
!err.message.includes('received undefined'),
)
.map(err => {
const typeErr = err as { expected: string }
const receivedMatch = err.message.match(/received (\w+)/)
const received = receivedMatch ? receivedMatch[1] : 'unknown'
return {
param: formatValidationPath(err.path),
expected: typeErr.expected,
received,
}
})
// Default to original error message if we can't create a better one
let errorContent = error.message
// Build a human-readable error message
const errorParts = []
if (missingParams.length > 0) {
const missingParamErrors = missingParams.map(
param => `The required parameter \`${param}\` is missing`,
)
errorParts.push(...missingParamErrors)
}
if (unexpectedParams.length > 0) {
const unexpectedParamErrors = unexpectedParams.map(
param => `An unexpected parameter \`${param}\` was provided`,
)
errorParts.push(...unexpectedParamErrors)
}
if (typeMismatchParams.length > 0) {
const typeErrors = typeMismatchParams.map(
({ param, expected, received }) =>
`The parameter \`${param}\` type is expected as \`${expected}\` but provided as \`${received}\``,
)
errorParts.push(...typeErrors)
}
if (errorParts.length > 0) {
errorContent = `${toolName} failed due to the following ${errorParts.length > 1 ? 'issues' : 'issue'}:\n${errorParts.join('\n')}`
}
return errorContent
}