pulumi/pulumi · error · fs.ErrNotExist

%w: %w

Error message

%w: %w

What it means

In the ACP filesystem ReadFileOverride path (pkg/cmd/pulumi/neo/acp/fs.go:101), when the editor-side read fails and the file also does not exist on local disk, the original editor error is wrapped with fs.ErrNotExist so callers see a standard not-found error. This satisfies the contract that missing files surface as errors.Is(err, fs.ErrNotExist), which the edit tool's creation mode depends on.

Source

Thrown at pkg/cmd/pulumi/neo/acp/fs.go:101

// ReadTextFile fetches the full content of an absolute path from the editor via
// the ACP `fs/read_text_file` request. Its signature matches
// tools.Filesystem.ReadFileOverride, so it can be assigned to that field
// directly, and it honors that field's contract of reporting missing files
// with an error satisfying errors.Is(err, fs.ErrNotExist).
func (c *ClientFS) ReadTextFile(ctx context.Context, path string) (string, error) {
	var res readTextFileResult
	if err := c.Caller.Call(ctx, "fs/read_text_file", readTextFileParams{
		SessionID: c.SessionID,
		Path:      path,
	}, &res); err != nil {
		// ACP doesn't standardize a "file not found" error code, but the
		// ReadFileOverride contract requires missing files to surface as
		// fs.ErrNotExist (the edit tool's creation mode depends on it). The
		// editor's view is local disk plus its open buffers, so when the editor
		// couldn't read the file and it isn't on disk either, it doesn't exist.
		if _, statErr := os.Stat(path); errors.Is(statErr, fs.ErrNotExist) {
			return "", fmt.Errorf("%w: %w", fs.ErrNotExist, err)
		}
		return "", err
	}
	return res.Content, nil
}

View on GitHub (pinned to 793f7b2e16)

Solutions

  1. If creating a new file, this error is expected: proceed with the edit tool's creation mode, which checks for fs.ErrNotExist.
  2. Verify the path is correct and relative to the session's working directory; list the directory to confirm the intended file location.
  3. If the file should exist, refresh the editor's open buffers/revert unsaved state and retry — a stale buffer path can mask an on-disk rename or delete.
  4. Re-run the operation after the file is restored or the path corrected.

Example fix

// caller-side handling
content, err := readFile(path)
if errors.Is(err, fs.ErrNotExist) {
    // create the file instead of editing
    return createFile(path, newContent)
}
Defensive patterns

Strategy: type-guard

Validate before calling

if _, err := os.Stat(path); errors.Is(err, fs.ErrNotExist) {
    // file missing before the call: use edit-tool creation mode
}

Type guard

func isFileNotFound(err error) bool { return errors.Is(err, fs.ErrNotExist) }

Try / catch

content, err := reader.ReadFile(ctx, path)
if errors.Is(err, fs.ErrNotExist) {
    return createFile(path, defaultContent)
}
if err != nil { return err }

Prevention

When it happens

Trigger: The edit tool attempts to read a file via the editor override, the editor reports failure, and os.Stat(path) confirms the file is absent — the returned error then wraps fs.ErrNotExist.

Common situations: Creating a brand-new file with the edit tool (expected path — creation mode relies on ErrNotExist), typos in file paths, or files deleted on disk but still shown open in the editor.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of pulumi/pulumi@793f7b2e16 (2026-08-31). Data as JSON: /api/errors/3d0bfa214effe25e. Report an issue: GitHub.