air-verse/air · error
unexpected error while dereferencing %v: %w
Error message
unexpected error while dereferencing %v: %w
What it means
After absolutizing, expandPath calls filepath.EvalSymlinks to dereference the path. EvalSymlinks errors that are NOT fs.ErrNotExist (e.g. ELOOP symlink cycles, EACCES) are unexpected and returned wrapped in this error.
Source
Thrown at runner/util.go:290
if strings.HasPrefix(path, "~/") {
home := os.Getenv("HOME")
expanded = filepath.Join(home, path[1:])
}
expanded, err := filepath.Abs(expanded)
if err != nil {
return "", fmt.Errorf("error getting absolute path to %v: %w", expanded, err)
}
// filepath.EvalSymlinks only works on real files
dereferenced, err := filepath.EvalSymlinks(expanded)
if err == nil {
return dereferenced, nil
}
if !errors.Is(err, fs.ErrNotExist) {
return "", fmt.Errorf("unexpected error while dereferencing %v: %w", expanded, err)
}
return expanded, nil
}
func isDir(path string) bool {
i, err := os.Stat(path)
if err != nil {
return false
}
return i.IsDir()
}
func validEvent(ev fsnotify.Event) bool {
return ev.Op&fsnotify.Create == fsnotify.Create ||
ev.Op&fsnotify.Write == fsnotify.Write ||
ev.Op&fsnotify.Remove == fsnotify.Remove ||
ev.Op&fsnotify.Rename == fsnotify.RenameView on GitHub (pinned to 71ea1dee05)
Solutions
- Inspect the wrapped %w error (syscall.ELOOP → symlink cycle; EACCES → permissions) and fix accordingly
- Remove or repair circular symlinks in the path (`find -L . -type l` can help locate loops)
- Check permissions on every path component (`ls -la` each ancestor)
- Bypass the symlink by configuring air with the real, non-symlinked path
Example fix
// before: project is a symlink loop ln -s proj proj-link && ln -s proj-link proj // after: point config at the real directory root = "/home/user/proj" // actual directory, not a loop
Defensive patterns
Strategy: try-catch
Validate before calling
// check the path resolves cleanly before handing it to air
resolved, err := filepath.EvalSymlinks(projectDir)
if err != nil {
return fmt.Errorf("project path not resolvable: %w", err)
}
_ = resolved Try / catch
_, err := filepath.EvalSymlinks(dir)
if err != nil {
switch {
case errors.Is(err, syscall.ELOOP):
// fix symlink cycle
case errors.Is(err, fs.ErrPermission):
// fix permissions
}
return err
} Prevention
- Avoid symlink loops in project or home directories
- Point air at real directories rather than chains of symlinks
- Keep parent directories of the project readable/executable
- Audit paths with `ls -la` and `find -L -type l` after environment changes
When it happens
Trigger: expandPath receives a path whose symlink resolution fails with a non-ErrNotExist error: a symlink loop, permission denied on a parent directory, or too many levels of symbolic links during config preprocessing.
Common situations: Circular symlinks in the project or home directory; a symlinked project path where a component is unreadable after a permissions change; NFS/mount issues making components inaccessible.
Related errors
- error getting absolute path to %v: %w
- failed to check for existing configuration: %w
- failed to create a new configuration: %w
- failed to write to %s: %w
AI-assisted analysis of air-verse/air@71ea1dee05 (2026-08-31).
Data as JSON: /api/errors/a66df70663e6c25e.
Report an issue: GitHub.