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

old_string and new_string must differ

Error message

old_string and new_string must differ

What it means

`edit_file` (runtime/src/file_ops.rs:277) rejects edits where `old_string == new_string` by exact byte equality, before it even checks that old_string exists. This is a no-op guard: a replacement that changes nothing is almost always a caller bug. `ErrorKind::InvalidInput`.

Source

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

        file_path: absolute_path.to_string_lossy().into_owned(),
        content: content.to_owned(),
        structured_patch: make_patch(original_file.as_deref().unwrap_or(""), content),
        original_file,
        git_diff: None,
    })
}

/// 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)?;

View on GitHub (pinned to 08106b0c37)

Solutions

  1. Skip the edit when the strings are equal instead of calling edit_file.
  2. If you intended a change, inspect both strings — invisible differences (or their absence) mean you pasted the same text twice.
  3. For wholesale rewrites with identical intent, use write_file only when content actually differs.

Example fix

// before
edit_file(path, &old, &new, false)?;   // old_string and new_string must differ

// after
if old != new {
    edit_file(path, &old, &new, false)?;
}
Defensive patterns

Strategy: validation

Validate before calling

if old_string != new_string {
    let out = edit_file(path, old_string, new_string, replace_all)?;
} else {
    // no-op edit: skip (or treat as idempotent success)
}

Try / catch

if let Err(e) = edit_file(path, old, new, false) {
    if e.kind() == std::io::ErrorKind::InvalidInput
        && e.to_string().contains("must differ") { /* skip as no-op */ } else { return Err(e); }
}

Prevention

When it happens

Trigger: Templating code that substitutes a placeholder with a value that turns out equal to the placeholder; retrying an already-applied edit with the same strings; a copy-paste mistake putting the same snippet in both fields.

Common situations: Agent loops computing new_string from old_string and hitting the identity case; idempotent re-run of a patch script that does not track whether it already applied.

Related errors


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