wavetermdev/waveterm · error

edit %d (%s): %s

Error message

edit %d (%s): %s

What it means

ApplyEdits applies a list of EditSpec operations in order; if any edit does not apply (e.g. its search text was not found), the whole batch is aborted and this error reports the edit index, its description, and the underlying reason. No partial application happens through this path (use ReplaceInFilePartial for partial application).

Source

Thrown at pkg/util/fileutil/fileutil.go:304

		result.Error = fmt.Sprintf("old_str appears %d times, must appear exactly once", count)
		return content, result
	}

	modifiedContent := bytes.Replace(content, oldBytes, []byte(edit.NewStr), 1)
	result.Applied = true
	return modifiedContent, result
}

// ApplyEdits applies a series of edits to the given content and returns the modified content.
// This is atomic - all edits succeed or all fail.
func ApplyEdits(originalContent []byte, edits []EditSpec) ([]byte, error) {
	modifiedContents := originalContent

	for i, edit := range edits {
		var result EditResult
		modifiedContents, result = applyEdit(modifiedContents, edit, i)
		if !result.Applied {
			return nil, fmt.Errorf("edit %d (%s): %s", i, result.Desc, result.Error)
		}
	}

	return modifiedContents, nil
}

// ApplyEditsPartial applies edits incrementally, continuing until the first failure.
// Returns the modified content (potentially partially applied) and results for each edit.
func ApplyEditsPartial(originalContent []byte, edits []EditSpec) ([]byte, []EditResult) {
	modifiedContents := originalContent
	results := make([]EditResult, len(edits))
	failed := false

	for i, edit := range edits {
		if failed {
			results[i].Desc = edit.Desc
			if results[i].Desc == "" {
				results[i].Desc = fmt.Sprintf("Edit %d", i+1)

View on GitHub (pinned to a4447c1563)

Solutions

  1. Re-read the current file content and regenerate the edit with the exact current text.
  2. Check the reported edit index and Desc to find which EditSpec failed; fix its search string.
  3. Split the batch and run edits individually to isolate the failing one.
  4. Use ReplaceInFilePartial if you want earlier edits to be applied despite a later failure.

Example fix

// before
edits := []fileutil.EditSpec{{Search: "oldPort := 8080"}} // no longer in file
_, err := fileutil.ApplyEdits(contents, edits)

// after
contents, _ := os.ReadFile(path)
if !strings.Contains(string(contents), "oldPort := 8080") {
    return errors.New("file changed; refresh edit search text")
}
_, err := fileutil.ApplyEdits(contents, edits)
Defensive patterns

Strategy: validation

Validate before calling

// verify each edit's search text exists before applying
for _, e := range edits {
    if !strings.Contains(string(contents), e.Search) {
        return fmt.Errorf("search text %q not found in file", e.Search)
    }
}

Try / catch

// Go: identify the failing edit from the message
if _, err := fileutil.ApplyEdits(contents, edits); err != nil {
    var idx int
    if n, _ := fmt.Sscanf(err.Error(), "edit %d", &idx); n == 1 {
        log.Printf("edit #%d failed: %v", idx, err)
        // regenerate edits[idx] from fresh file content and retry
    }
}

Prevention

When it happens

Trigger: Calling ReplaceInFile/EditTextFileDryRun with an EditSpec whose search string does not match the current content, matches ambiguously where uniqueness was required, or is otherwise rejected by applyEdit; the failing edit is identified by its zero-based index in the edits slice.

Common situations: Editing a file whose content changed since the edit was drafted (stale search text); whitespace/indentation mismatches; edits computed against a different file version; duplicate search strings when a unique match is required.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/2b96080693033504. Report an issue: GitHub.