charmbracelet/crush · error
error accessing file: %w
Error message
error accessing file: %w
What it means
os.Stat(filePath) failed with an error other than NotExist (those become friendly "File not found" text responses with suggestions). The wrapped errno tells you what else went wrong — permission denied on a path component, too many symlinks, I/O error, etc.
Source
Thrown at internal/agent/tools/view.go:186
for _, entry := range dirEntries {
if strings.Contains(strings.ToLower(entry.Name()), strings.ToLower(base)) ||
strings.Contains(strings.ToLower(base), strings.ToLower(entry.Name())) {
suggestions = append(suggestions, filepath.Join(dir, entry.Name()))
if len(suggestions) >= 3 {
break
}
}
}
if len(suggestions) > 0 {
return fantasy.NewTextErrorResponse(fmt.Sprintf("File not found: %s\n\nDid you mean one of these?\n%s",
filePath, strings.Join(suggestions, "\n"))), nil
}
}
return fantasy.NewTextErrorResponse(fmt.Sprintf("File not found: %s", filePath)), nil
}
return fantasy.ToolResponse{}, fmt.Errorf("error accessing file: %w", err)
}
// Check if it's a directory
if fileInfo.IsDir() {
return fantasy.NewTextErrorResponse(fmt.Sprintf("Path is a directory, not a file: %s", filePath)), nil
}
// Set default limit if not provided (no limit for SKILL.md files)
if params.Limit <= 0 {
if isSkillFile {
params.Limit = 1000000 // Effectively no limit for skill files
} else {
params.Limit = DefaultReadLimit
}
}
isSupportedImage, mimeType := getImageMimeType(filePath)
if isSupportedImage {View on GitHub (pinned to 7944b8e522)
Solutions
- Read the wrapped cause: EACCES → fix permissions (chmod/chown or run with access); ELOOP → fix the symlink; ENOTDIR → correct the path
- Verify each path component with ls/stat as the same user the process runs as
- Pick a readable copy of the file instead of the protected one
- If outside the workdir, ensure the read permission request was granted — though denial normally yields a different response
Example fix
// before
{"file_path":"/root/.ssh/id_rsa"} // stat: permission denied
// after
chmod o+r /path/to/readable/file # or read a copy the user can access
{"file_path":"/home/user/project/file.txt"} Defensive patterns
Strategy: fallback
Validate before calling
if _, err := os.Stat(path); err != nil && !os.IsNotExist(err) {
// EACCES/ELOOP/ENOTDIR etc. — resolve before calling the tool
return fmt.Errorf("path %q not accessible: %w", path, err)
} Type guard
func isAccessibleFile(path string) bool {
st, err := os.Stat(path)
return err == nil && !st.IsDir()
} Try / catch
var pe *fs.PathError
if errors.As(err, &pe) {
switch pe.Err {
case syscall.EACCES: // fix permissions / read an accessible copy
case syscall.ELOOP: // fix symlink loop
case syscall.ENOTDIR: // correct the path
}
} Prevention
- Pre-check readability with a stat/open probe as the same user
- Avoid pointing the tool at root-owned or mode-0600 system files
- Check for symlink loops before reading link-heavy paths
- Grant the out-of-workdir read permission when prompted
When it happens
Trigger: Reading a file whose parent directory (or the file) lacks read/search permission (EACCES), a symlink loop (ELOOP), a path component that is not a directory (ENOTDIR), or device I/O errors.
Common situations: Files under directories with restrictive permissions (root-owned, SSH keys, system dirs); broken mount points; macOS/SELinux sandbox denials; paths with a regular file where a directory is expected.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- failed to access file: %w
- failed to create parent directories: %w
- failed to create output file: %w
- failed to create parent directories: %w
- session ID is required for accessing directories outside wor
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/c4f0ea111d8a2901.
Report an issue: GitHub.