wavetermdev/waveterm · error

not a regular file: %s

Error message

not a regular file: %s

What it means

Returned when the path exists but is not a regular file (e.g. it is a directory, symlink to a device, socket, or pipe) and a regular file is required for the operation. The path is included via %s.

Source

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

		}

		modifiedContents, results[i] = applyEdit(modifiedContents, edit, i)
		if !results[i].Applied {
			failed = true
		}
	}

	return modifiedContents, results
}

func ReplaceInFile(filePath string, edits []EditSpec) error {
	fileInfo, err := os.Stat(filePath)
	if err != nil {
		return fmt.Errorf("failed to stat file: %w", err)
	}

	if !fileInfo.Mode().IsRegular() {
		return fmt.Errorf("not a regular file: %s", filePath)
	}

	if fileInfo.Size() > MaxEditFileSize {
		return fmt.Errorf("file too large for editing: %d bytes (max: %d)", fileInfo.Size(), MaxEditFileSize)
	}

	contents, err := os.ReadFile(filePath)
	if err != nil {
		return fmt.Errorf("failed to read file: %w", err)
	}

	modifiedContents, err := ApplyEdits(contents, edits)
	if err != nil {
		return err
	}

	if err := os.WriteFile(filePath, modifiedContents, fileInfo.Mode()); err != nil {
		return fmt.Errorf("failed to write file: %w", err)

View on GitHub (pinned to a4447c1563)

Solutions

  1. Point filePath at an actual file, not a directory or special file.
  2. If a directory was given, resolve to the concrete file inside it (e.g. the settings JSON).
  3. Check with os.Stat and FileInfo.Mode().IsRegular() before calling.
  4. Skip special files in any path-walking code that feeds ReplaceInFile.

Example fix

// before
fileutil.ReplaceInFile("/home/user/.config/wave", edits) // directory

// after
fi, _ := os.Stat(path)
if !fi.Mode().IsRegular() {
    path = filepath.Join(path, "settings.json")
}
fileutil.ReplaceInFile(path, edits)
Defensive patterns

Strategy: validation

Validate before calling

fi, err := os.Stat(path)
if err == nil && !fi.Mode().IsRegular() {
    return fmt.Errorf("refusing to edit non-regular file: %s", path)
}

Try / catch

// Go: check message or pre-validate mode
if err := fileutil.ReplaceInFile(path, edits); err != nil {
    if strings.Contains(err.Error(), "not a regular file") {
        return fmt.Errorf("pass a concrete file path, not %s", path)
    }
}

Prevention

When it happens

Trigger: Calling ReplaceInFile with a directory path, a device node (/dev/...), a named pipe, or a unix socket as filePath.

Common situations: Passing a directory where a file was expected (e.g. ~/.config/wave instead of a settings file); resolving a glob or user input to a special file; editing paths under /proc or /sys.

Related errors


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