googleapis/mcp-toolbox · error
local path %q cannot be resolved for source %q: %w
Error message
local path %q cannot be resolved for source %q: %w
What it means
validateLocalPath could not resolve symbolic links along the local path when checking it against the source's allowed local roots. The wrapped OS error (from ResolveSymlinks, typically *PathError with ENOENT/EACCES/ELOOP) tells the real reason. The path passed the name-level match but symlink resolution failed, so access is denied conservatively.
Source
Thrown at internal/sources/cloudstorage/cloudstorage.go:138
}
if len(s.AllowedLocalRoots) == 0 {
return nil
}
nameMatched := false
for _, root := range s.AllowedLocalRoots {
if isUnderRoot(clean, root) {
nameMatched = true
break
}
}
if !nameMatched {
return fmt.Errorf("local path %q is not under any allowed local roots for source %q", p, s.Name)
}
resolved, err := cloudstoragecommon.ResolveSymlinks(clean)
if err != nil {
return fmt.Errorf("local path %q cannot be resolved for source %q: %w", p, s.Name, err)
}
for _, root := range s.AllowedLocalRoots {
// A root we cannot resolve authorizes nothing; skip it rather than
// falling back to the name-level match we already passed.
resolvedRoot, err := cloudstoragecommon.ResolveSymlinks(root)
if err != nil {
continue
}
if isUnderRoot(resolved, resolvedRoot) {
return nil
}
}
return fmt.Errorf("local path %q resolves through a symbolic link to a target outside the allowed local roots for source %q", p, s.Name)
}
func isUnderRoot(target, root string) bool {
target = filepath.Clean(target)
root = filepath.Clean(root)View on GitHub (pinned to 8cc6e09de2)
Solutions
- Check the wrapped %w error: create missing directories (os.MkdirAll) or fix the path typo before calling DownloadObject/UploadObject.
- Fix filesystem permissions so the process user can traverse every path component.
- Remove or repair the symlink loop or dangling symlink (readlink -f <path> to reproduce).
- If the root itself is unresolvable, correct the allowed_local_roots configuration to point at existing real directories.
Example fix
// before
err := source.UploadObject(ctx, "bkt", "obj", "/data/out/missing/file.bin")
// after
if err := os.MkdirAll("/data/out", 0o755); err != nil { return err }
err := source.UploadObject(ctx, "bkt", "obj", "/data/out/file.bin") Defensive patterns
Strategy: validation
Validate before calling
p := "/data/out/file.bin"
if _, err := filepath.EvalSymlinks(p); err != nil {
return fmt.Errorf("path not resolvable: %w", err)
} Try / catch
var pathErr *fs.PathError
if errors.As(err, &pathErr) && errors.Is(pathErr.Err, syscall.ENOENT) {
// create missing dirs / fix path
} Prevention
- Create destination directories (os.MkdirAll) before calling DownloadObject.
- Run the server with a user that has traverse permissions on all configured roots.
- Audit configured roots with `readlink -f` to ensure they resolve.
When it happens
Trigger: Calling DownloadObject or UploadObject (which invoke validateLocalPath) with a local path whose symlinks cannot be resolved: the path (or an ancestor) does not exist, the process lacks search permission on a directory component, or a symlink loop (ELOOP, >40 levels) exists.
Common situations: Typoed or not-yet-created download destination; downloading into a directory removed at runtime; running the server as a user without execute permission on a parent directory (e.g. /root/...); a dangling symlink created by another process; broken symlink chain in a container with a stale volume mount.
Related errors
- path %q cannot be resolved: %w
- local path %q resolves through a symbolic link to a target o
- path %q resolves through a symbolic link to a target outside
- unable to read config file at %q: %w
- unable to access config folder at %q: %w
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/fbcc075eaf6416ad.
Report an issue: GitHub.