ultraworkers/claw-code · error · std::io::Error

old_string not found in file

Error message

old_string not found in file

What it means

`edit_file` (runtime/src/file_ops.rs:283) requires the file's current contents to contain `old_string` as an exact byte substring (no whitespace normalization) and returns `ErrorKind::NotFound` otherwise. Note this port has NO multiple-match ambiguity error: without `replace_all` it replaces the FIRST occurrence via `replacen(.., 1)`.

Source

Thrown at rust/crates/runtime/src/file_ops.rs:283

}

/// Performs an in-file string replacement and returns patch metadata.
pub fn edit_file(
    path: &str,
    old_string: &str,
    new_string: &str,
    replace_all: bool,
) -> io::Result<EditFileOutput> {
    let absolute_path = normalize_path(path)?;
    let original_file = fs::read_to_string(&absolute_path)?;
    if old_string == new_string {
        return Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "old_string and new_string must differ",
        ));
    }
    if !original_file.contains(old_string) {
        return Err(io::Error::new(
            io::ErrorKind::NotFound,
            "old_string not found in file",
        ));
    }

    let updated = if replace_all {
        original_file.replace(old_string, new_string)
    } else {
        original_file.replacen(old_string, new_string, 1)
    };
    fs::write(&absolute_path, &updated)?;

    Ok(EditFileOutput {
        file_path: absolute_path.to_string_lossy().into_owned(),
        old_string: old_string.to_owned(),
        new_string: new_string.to_owned(),
        original_file: original_file.clone(),
        structured_patch: make_patch(&original_file, &updated),

View on GitHub (pinned to 08106b0c37)

Solutions

  1. Re-read the file now and copy old_string verbatim from the fresh content.
  2. Widen old_string with surrounding unique context lines so it matches exactly.
  3. Pre-check with the same substring test before calling, and re-verify tabs/CRLF with `cat -A file | head`.

Example fix

# before (stale copy: file changed since read)
Edit(file="src/lib.rs", old_string="fn main() {\n    println!(\"hi\")", ...)

# after (re-read, then anchor on current exact bytes)
Read(file="src/lib.rs")
Edit(file="src/lib.rs", old_string="fn main() {\n    println!(\"hello\")", ...)
Defensive patterns

Strategy: validation

Validate before calling

let current = std::fs::read_to_string(path)?;
if !current.contains(old_string) {
    // re-copy old_string from `current` (exact bytes, no normalization) before editing
}

Try / catch

match edit_file(path, old, new, replace_all) {
    Err(e) if e.kind() == std::io::ErrorKind::NotFound
        && e.to_string().contains("old_string not found") => { /* re-read file, rebuild old_string from fresh bytes */ }
    other => other,
}

Prevention

When it happens

Trigger: The file changed between the read that produced old_string and the edit (stale buffer); tabs vs spaces; trailing whitespace or line-ending differences; copied old_string from rendered output that collapsed spacing; wrong file path (edited a different copy).

Common situations: Concurrent formatters/linters rewriting the file mid-session; agent editing from an outdated file snapshot; CRLF files edited with LF-anchored strings; monorepo duplicate paths.

Related errors


AI-assisted analysis of ultraworkers/claw-code@08106b0c37 (2026-08-18). Data as JSON: /api/errors/ed06118c8bedc049. Report an issue: GitHub.