larksuite/cli · error
cannot resolve symlinks: %w
Error message
cannot resolve symlinks: %w
What it means
SafeEnvDirPath resolves symlinks through the nearest existing ancestor of the directory. If Lstat/EvalSymlinks on that ancestor chain fails (permission denied on a component, I/O error, or a symlink loop the resolver cannot evaluate), the function fails closed and wraps the OS error with this message.
Source
Thrown at internal/vfs/localfileio/path.go:137
return value, nil
}
// SafeEnvDirPath validates an environment-provided application directory path.
// It requires an absolute path, rejects control characters, normalizes the
// input, and resolves symlinks through the nearest existing ancestor.
func SafeEnvDirPath(path, envName string) (string, error) {
if err := charcheck.RejectControlChars(path, envName); err != nil {
return "", err
}
path = filepath.Clean(path)
if !filepath.IsAbs(path) {
return "", fmt.Errorf("%s must be an absolute path, got %q", envName, path)
}
resolved, err := resolveNearestAncestor(path)
if err != nil {
return "", fmt.Errorf("cannot resolve symlinks: %w", err)
}
return resolved, nil
}
// safePath is the shared implementation for SafeOutputPath and SafeInputPath.
// A path is accepted when its real location falls inside the built-in
// allowlist (cwd, /tmp, ~/files) and outside the built-in denylist; deny wins
// over allow, cwd included. Both lists are compiled in (policy.go), which
// also documents the two bounded environment inputs that remain.
func safePath(raw, flagName string) (string, error) {
isOutputFlag := flagName == "--output"
if err := charcheck.RejectControlChars(raw, flagName); err != nil {
return "", err
}
if strings.TrimSpace(raw) == "" {
return "", fmt.Errorf("%s must not be empty", flagName)
}
if err := validatePathPlatform(raw); err != nil {View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Check permissions on each path component: `namei -l /the/path` and fix with chmod/chown
- Inspect the chain for symlink loops: `ls -la` each component and remove the offending link
- Verify the mount is active (mount / df) if the path lives on a network or automounted volume
- Point the env var at a simpler path without symlinks
Example fix
# before export LARK_APP_DIR=/mnt/nfs/app # NFS server down # error: cannot resolve symlinks: lstat /mnt/nfs: no such file or directory # after (mount recovered) or: export LARK_APP_DIR=/opt/local/app
Defensive patterns
Strategy: fallback
Validate before calling
if _, err := filepath.EvalSymlinks(existingPrefix(v)); err != nil {
return fmt.Errorf("cannot resolve %q: %w", v, err)
} Try / catch
dir, err := localfileio.SafeEnvDirPath(os.Getenv("MY_APP_DIR"), "MY_APP_DIR")
if err != nil && strings.Contains(err.Error(), "cannot resolve symlinks") {
dir = fallbackDir // e.g. "/opt/myapp"
} Prevention
- Check component permissions with namei -l when paths fail
- Avoid symlink loops and stale network mount points in configured paths
- Prefer plain, symlink-free directories for app state
When it happens
Trigger: Calling SafeEnvDirPath where resolveNearestAncestor hits an unreadable parent directory (EACCES), a symlink cycle, or a stale automount/NFS mount point on the path.
Common situations: Env var pointing into another user's home with no search permission; a broken symlink loop in the ancestor chain; network mounts that dropped; paths under /media or automounted dirs that are currently offline.
Related errors
- %s: path %q is a symlink (not allowed)
- %s: cannot resolve symlink %q: %w
- %s: cannot stat resolved path %q: %w
- %s: resolved path %q is still a symlink
- %s: cannot stat %q: %w
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/0053d5b33486e5ca.
Report an issue: GitHub.