{"record":{"id":"fbcc075eaf6416ad","repo":"googleapis/mcp-toolbox","slug":"local-path-q-cannot-be-resolved-for-source-q-w","errorCode":null,"errorMessage":"local path %q cannot be resolved for source %q: %w","messagePattern":"local path %q cannot be resolved for source %q: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/sources/cloudstorage/cloudstorage.go","lineNumber":138,"sourceCode":"\t}\n\tif len(s.AllowedLocalRoots) == 0 {\n\t\treturn nil\n\t}\n\n\tnameMatched := false\n\tfor _, root := range s.AllowedLocalRoots {\n\t\tif isUnderRoot(clean, root) {\n\t\t\tnameMatched = true\n\t\t\tbreak\n\t\t}\n\t}\n\tif !nameMatched {\n\t\treturn fmt.Errorf(\"local path %q is not under any allowed local roots for source %q\", p, s.Name)\n\t}\n\n\tresolved, err := cloudstoragecommon.ResolveSymlinks(clean)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"local path %q cannot be resolved for source %q: %w\", p, s.Name, err)\n\t}\n\tfor _, root := range s.AllowedLocalRoots {\n\t\t// A root we cannot resolve authorizes nothing; skip it rather than\n\t\t// falling back to the name-level match we already passed.\n\t\tresolvedRoot, err := cloudstoragecommon.ResolveSymlinks(root)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tif isUnderRoot(resolved, resolvedRoot) {\n\t\t\treturn nil\n\t\t}\n\t}\n\treturn fmt.Errorf(\"local path %q resolves through a symbolic link to a target outside the allowed local roots for source %q\", p, s.Name)\n}\n\nfunc isUnderRoot(target, root string) bool {\n\ttarget = filepath.Clean(target)\n\troot = filepath.Clean(root)","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/sources/cloudstorage/cloudstorage.go#L120-L156","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nerr := source.UploadObject(ctx, \"bkt\", \"obj\", \"/data/out/missing/file.bin\")\n// after\nif err := os.MkdirAll(\"/data/out\", 0o755); err != nil { return err }\nerr := source.UploadObject(ctx, \"bkt\", \"obj\", \"/data/out/file.bin\")","handlingStrategy":"validation","validationCode":"p := \"/data/out/file.bin\"\nif _, err := filepath.EvalSymlinks(p); err != nil {\n    return fmt.Errorf(\"path not resolvable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"var pathErr *fs.PathError\nif errors.As(err, &pathErr) && errors.Is(pathErr.Err, syscall.ENOENT) {\n    // create missing dirs / fix path\n}","preventionTips":["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."],"tags":["filesystem","symlink","path-resolution","cloudstorage"],"backgroundTag":"symlink-resolution-failed","analyzedSha":"8cc6e09de2ad7b8bffc77751799585a1401a48eb","analyzedAt":"2026-09-05T01:10:36.887Z","contentChangedAt":"2026-09-05T01:10:36.887Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}