JuliusBrussee/caveman · warning · Error
caveman-code: old_string and new_string are identical
Error message
caveman-code: old_string and new_string are identical
What it means
edit_file refuses a no-op edit: old_string and new_string must differ byte-for-byte. This is an upfront guard so callers notice malformed edit requests (e.g. a template that substitutes the same value into both fields) before any disk write is attempted.
Source
Thrown at packages/agent/src/code.ts:343
});
const editTool = tool({
name: "edit_file",
description:
"Replace an exact string in a workspace file. The old string must appear exactly " +
"once unless replace_all is set. Writes to disk.",
input: schema.object({
path: schema.string(),
old_string: schema.string(),
new_string: schema.string(),
replace_all: schema.optional(schema.boolean()),
}),
effect: "write",
result: "inline",
timeoutMs: READ_TIMEOUT_MS,
async execute(input) {
if (input.old_string === input.new_string) {
throw new Error("caveman-code: old_string and new_string are identical");
}
const target = await contained(input.path);
const content = await readFile(target, "utf8");
const occurrences = content.split(input.old_string).length - 1;
if (occurrences === 0) {
throw new Error(`caveman-code: old_string not found in ${input.path}`);
}
if (occurrences > 1 && input.replace_all !== true) {
throw new Error(
`caveman-code: old_string appears ${occurrences} times in ${input.path}; ` +
"add surrounding context or pass replace_all",
);
}
// split/join UNCONDITIONALLY. String.prototype.replace
// interprets `$&`, `$\``, `$'`, `$$`, `$1`… in the REPLACEMENT even for a
// string pattern, so a new_string containing any of them would silently
// corrupt the file. The non-replace_all branch is guaranteed exactly one
// occurrence above, so joining replaces precisely that one.View on GitHub (pinned to 27d5a3981a)
Solutions
- Diff your old/new strings before calling edit_file; if they are equal, the edit is unnecessary — skip it
- Fix the upstream templating/substitution bug that made the two fields collapse to the same value
- If you intended a no-op touch (e.g. mtime), use a different mechanism — edit_file will never allow it
Example fix
// before
await edit_file({ path, old_string: snippet, new_string: snippet });
// after
if (oldString !== newString) {
await edit_file({ path, old_string: oldString, new_string: newString });
} Defensive patterns
Strategy: validation
Validate before calling
function assertEditDiffers(old_string: string, new_string: string): void {
if (old_string === new_string) throw new Error("edit is a no-op; old_string equals new_string");
} Prevention
- Diff old/new before calling edit_file and skip identical pairs
- In generated edit pipelines, assert the computed replacement actually differs from the anchor
When it happens
Trigger: Calling edit_file with identical old_string and new_string values — typically a scripted caller whose before/after variables collapsed to the same content, or a model emitting a placeholder edit.
Common situations: Code-generation loops producing degenerate edits; templating where the substitution failed and both placeholders rendered identically; refactoring scripts that computed new content equal to existing content.
Related errors
- caveman-code: old_string not found in ${input.path}
- caveman-code: old_string appears ${occurrences} times in ${i
- cave_agent_definition_invalid
- option not found
- cave_harness_adapter_version_invalid
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/d5fd6345a75e245e.
Report an issue: GitHub.