charmbracelet/crush · error

failed to access file: %w

Error message

failed to access file: %w

What it means

In createNewFile (edit tool, new-file mode), os.Stat returned an error that is neither nil nor os.IsNotExist, meaning file accessibility could not be determined. The tool aborts rather than risk overwriting an existing file it cannot inspect. Expected errors (file exists / not exists) are handled separately.

Source

Thrown at internal/agent/tools/edit.go:115

			notifyLSPs(ctx, lspManager, params.FilePath)

			text := fmt.Sprintf("<result>\n%s\n</result>\n", response.Content)
			text += getDiagnostics(params.FilePath, lspManager)
			response.Content = text
			return response, nil
		},
	)
}

func createNewFile(edit editContext, filePath, content string, call fantasy.ToolCall) (fantasy.ToolResponse, error) {
	fileInfo, err := os.Stat(filePath)
	if err == nil {
		if fileInfo.IsDir() {
			return fantasy.NewTextErrorResponse(fmt.Sprintf("path is a directory, not a file: %s", filePath)), nil
		}
		return fantasy.NewTextErrorResponse(fmt.Sprintf("file already exists: %s", filePath)), nil
	} else if !os.IsNotExist(err) {
		return fantasy.ToolResponse{}, fmt.Errorf("failed to access file: %w", err)
	}

	dir := filepath.Dir(filePath)
	if err = os.MkdirAll(dir, 0o755); err != nil {
		return fantasy.ToolResponse{}, fmt.Errorf("failed to create parent directories: %w", err)
	}

	sessionID := GetSessionFromContext(edit.ctx)
	if sessionID == "" {
		return fantasy.ToolResponse{}, fmt.Errorf("session ID is required for creating a new file")
	}

	_, additions, removals := diff.GenerateDiff(
		"",
		content,
		strings.TrimPrefix(filePath, edit.workingDir),
	)
	p, err := edit.permissions.Request(

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Check the wrapped error code (EACCES, ELOOP, ENAMETOOLONG) and fix the path accordingly
  2. Ensure all parent directories are traversable (r+x) by the running process
  3. Remove or repair symlink cycles in the path
  4. Shorten the path if NAME_MAX/PATH_MAX is exceeded

Example fix

// before
path: /root/secret/newfile.go  (running as unprivileged user)
// after
path: /home/user/project/newfile.go
Defensive patterns

Strategy: validation

Validate before calling

parent := filepath.Dir(target)
for p := parent; p != "/"; p = filepath.Dir(p) {
    fi, err := os.Stat(p)
    if err != nil {
        if os.IsNotExist(err) { continue } // will be created
        return fmt.Errorf("cannot inspect %s: %v", p, err)
    }
    if !fi.IsDir() { return fmt.Errorf("%s is not a directory", p) }
}

Try / catch

_, err := os.Stat(filePath)
if err != nil && !os.IsNotExist(err) {
    return fmt.Errorf("cannot determine if %s exists: %w", filePath, err)
} // proceed only when err == nil (exists → reject) or os.IsNotExist(err)

Prevention

When it happens

Trigger: os.Stat fails with EACCES/EACCES on a parent directory (permission denied while traversing the path), ELOOP from a symlink cycle, ENAMETOOLONG, or I/O errors on the filesystem — anything other than ErrNotExist.

Common situations: Creating a file inside a directory the process cannot read/execute; broken symlink loops in the path; very long paths; network filesystems returning transient stat errors.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/b3242362c9c20f0d. Report an issue: GitHub.