{"record":{"id":"b69284534cdca70b","repo":"googleapis/mcp-toolbox","slug":"path-q-traverses-unresolvable-symbolic-link-q","errorCode":null,"errorMessage":"path %q traverses unresolvable symbolic link %q","messagePattern":"path %q traverses unresolvable symbolic link %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/tools/cloudstorage/cloudstoragecommon/paths.go","lineNumber":90,"sourceCode":"// caller that opens the path afterwards is still racing anyone able to write\n// into the directories it traverses. Hard links are not detectable here at all.\n// Both remain the operator's to contain with OS permissions.\nfunc ResolveSymlinks(path string) (string, error) {\n\tresolved, err := filepath.EvalSymlinks(path)\n\tif err == nil {\n\t\treturn resolved, nil\n\t}\n\tif !errors.Is(err, fs.ErrNotExist) {\n\t\treturn \"\", fmt.Errorf(\"cannot resolve path %q: %w\", path, err)\n\t}\n\n\t// Walk up to the deepest ancestor that does resolve, remembering the\n\t// components we stepped over so they can be reattached to it.\n\tvar missing []string\n\tcur := path\n\tfor {\n\t\tif fi, lerr := os.Lstat(cur); lerr == nil && fi.Mode()&fs.ModeSymlink != 0 {\n\t\t\treturn \"\", fmt.Errorf(\"path %q traverses unresolvable symbolic link %q\", path, cur)\n\t\t}\n\t\tparent := filepath.Dir(cur)\n\t\tif parent == cur {\n\t\t\treturn \"\", fmt.Errorf(\"cannot resolve path %q: no existing ancestor\", path)\n\t\t}\n\t\tmissing = append([]string{filepath.Base(cur)}, missing...)\n\t\tcur = parent\n\n\t\tresolvedParent, perr := filepath.EvalSymlinks(cur)\n\t\tif perr == nil {\n\t\t\treturn filepath.Join(append([]string{resolvedParent}, missing...)...), nil\n\t\t}\n\t\tif !errors.Is(perr, fs.ErrNotExist) {\n\t\t\treturn \"\", fmt.Errorf(\"cannot resolve path %q: %w\", path, perr)\n\t\t}\n\t}\n}\n","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/tools/cloudstorage/cloudstoragecommon/paths.go#L72-L108","documentation":"While walking up to the deepest existing ancestor, ResolveSymlinks found a path component that exists as a symlink but does not resolve (a dangling link); creating a file there would follow the link, reopening the escape this check exists to close, so it is rejected.","triggerScenarios":"Thrown at internal/tools/cloudstorage/cloudstoragecommon/paths.go:90 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Remove or repair the dangling symlink named in the error","Point the symlink at an existing target inside the allowed area","Use a path that avoids the broken link"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"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"}