Project Files
src / git / error-formatting.ts
/**
* @const {string} Lowercase prefix git uses for fatal error messages on stderr.
* @default "fatal:"
*/
const fatalPrefix = "fatal:"
/**
* Cleans a simple-git error message and prefixes it with operation context so the
* caller LLM gets actionable information about which tool failed and where.
* Strips the noisy `fatal:` prefix that simple-git inherits from git's stderr,
* collapses multi-line output into one line, and rewrites a few common error
* patterns into clearer messages.
*
* @param operation The name of the failing tool (for example, `git_status`).
* @param target The target the operation was acting on, such as a repo name or URL.
* @param error The error caught from a simple-git call.
* @returns A formatted error string suitable for returning to the model.
*/
export function formatGitError(operation: string, target: string, error: unknown): string {
const rawMessage = error instanceof Error ? error.message : String(error)
const cleaned = rawMessage
.split("\n")
.map(line => {
const trimmed = line.trim()
return trimmed.toLowerCase().startsWith(fatalPrefix) ? trimmed.slice(fatalPrefix.length).trim() : trimmed
})
.filter(line => line.length > 0)
.join("; ")
const lower = cleaned.toLowerCase()
if (lower.includes("not a git repository")) {
return `Error: "${target}" is not a git repository or the directory does not exist within the working directory.`
}
if (lower.includes("already exists and is not an empty directory")) {
return `Error: ${operation} could not write to "${target}" because the destination already exists and is not empty. Choose a different repoName.`
}
if (lower.includes("could not resolve host") || lower.includes("could not read from remote")) {
return `Error: ${operation} could not reach "${target}". Check the URL and that the network is available. Cause: ${cleaned}`
}
if (lower.includes("authentication failed") || lower.includes("permission denied")) {
return `Error: ${operation} was denied access to "${target}". Authentication failed or the credentials lack permission.`
}
if (lower.includes("ambiguous argument") || lower.includes("bad object") || lower.includes("unknown revision")) {
return `Error: ${operation} could not resolve the requested ref or path in "${target}". Cause: ${cleaned}`
}
const suffix = cleaned.length > 0 ? `: ${cleaned}` : ""
return `Error: ${operation} failed for "${target}"${suffix}.`
}