charmbracelet/crush · error
cannot convert CWD to absolute path: %w
Error message
cannot convert CWD to absolute path: %w
What it means
traverseUp (used by Lookup and LookupClosest) converts the starting directory to an absolute path with filepath.Abs before walking. This error is returned when filepath.Abs fails, which happens only when os.Getwd fails while resolving a relative dir.
Source
Thrown at internal/fsext/lookup.go:166
found = append(found, fpath)
}
return nil
})
if err != nil {
return nil, err
}
return found, nil
}
// traverseUp walks up from given directory up until filesystem root reached.
// It passes absolute path of current directory and staring directory owner ID
// to callback function. It is up to user to check ownership.
func traverseUp(dir string, walkFn func(dir string, owner int) error) error {
cwd, err := filepath.Abs(dir)
if err != nil {
return fmt.Errorf("cannot convert CWD to absolute path: %w", err)
}
owner, err := Owner(dir)
if err != nil {
return fmt.Errorf("cannot get ownership: %w", err)
}
for {
err := walkFn(cwd, owner)
if err == nil || errors.Is(err, filepath.SkipDir) {
parent := filepath.Dir(cwd)
if parent == cwd {
return nil
}
cwd = parent
continue
}View on GitHub (pinned to 7944b8e522)
Solutions
- Pass an absolute path to Lookup instead of a relative one so filepath.Abs never needs os.Getwd
- Restore or recreate the process working directory, or chdir to a valid directory first
- Fix permissions on the current directory (chmod +x) or remount a failed filesystem
- Restart the process from a valid directory
Example fix
// before
found, err := fsext.Lookup(".", ".git")
// after
absDir, err := filepath.Abs("/project/root") // absolute input avoids Getwd
if err != nil {
return err
}
found, err := fsext.Lookup(absDir, ".git") Defensive patterns
Strategy: validation
Validate before calling
abs, err := filepath.Abs(dir) // fails only via Getwd for relative dir
if err != nil {
return fmt.Errorf("starting dir not resolvable: %w", err)
}
if _, err := os.Stat(abs); err != nil {
return fmt.Errorf("starting dir unavailable: %w", err)
} Type guard
func dirIsResolvable(dir string) bool {
abs, err := filepath.Abs(dir)
return err == nil && func() bool { _, err := os.Stat(abs); return err == nil }()
} Try / catch
found, err := fsext.Lookup(dir, targets...)
if err != nil {
if strings.Contains(err.Error(), "cannot convert CWD to absolute path") {
// fall back to absolute input path
if abs, aerr := filepath.Abs(dir); aerr == nil {
found, err = fsext.Lookup(abs, targets...)
}
}
if err != nil {
return err
}
} Prevention
- Always pass absolute paths to Lookup/LookupClosest
- Don't leave the process CWD pointing at deleted directories
- Ensure the runtime user has +x on all CWD ancestors
- On Linux, note os.Getwd can fail without $PWD set correctly; rely on absolute inputs
When it happens
Trigger: Passing a relative path (including "" or ".") to Lookup/LookupClosest while the process working directory is unreadable — e.g. the CWD directory was deleted, lacks execute permission, or is on a failed mount.
Common situations: Running the tool from a directory that was removed by another process (common after builds clean the tree); dropping into a directory without +x for the current user; containers with a deleted working directory.
Related errors
- cannot convert stop dir to absolute path: %w
- error resolving working directory: %w
- error resolving file path: %w
- failed to change directory: %v
- failed to get current working directory: %v
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/f149f5abf91a0d8f.
Report an issue: GitHub.