{"record":{"id":"c585d004b66b5ab9","repo":"gastownhall/beads","slug":"failed-to-resolve-path-w","errorCode":null,"errorMessage":"failed to resolve path: %w","messagePattern":"failed to resolve path: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/doctor/fix/common.go","lineNumber":117,"sourceCode":"}\n\n// safeWorkspacePath resolves relPath within the workspace root and ensures it\n// cannot escape the workspace via path traversal.\nfunc safeWorkspacePath(root, relPath string) (string, error) {\n\tabsRoot, err := filepath.Abs(root)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"invalid workspace path: %w\", err)\n\t}\n\n\tcleanRel := filepath.Clean(relPath)\n\tif filepath.IsAbs(cleanRel) {\n\t\treturn \"\", fmt.Errorf(\"expected relative path, got absolute: %s\", relPath)\n\t}\n\n\tjoined := filepath.Join(absRoot, cleanRel)\n\trel, err := filepath.Rel(absRoot, joined)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to resolve path: %w\", err)\n\t}\n\n\tif rel == \"..\" || strings.HasPrefix(rel, \"..\"+string(os.PathSeparator)) {\n\t\treturn \"\", fmt.Errorf(\"path escapes workspace: %s\", relPath)\n\t}\n\n\treturn joined, nil\n}\n\n// isWithinWorkspace reports whether candidate resides within the workspace root.\nfunc isWithinWorkspace(root, candidate string) bool {\n\tcleanRoot, err := filepath.Abs(root)\n\tif err != nil {\n\t\treturn false\n\t}\n\tcleanCandidate := filepath.Clean(candidate)\n\trel, err := filepath.Rel(cleanRoot, cleanCandidate)\n\tif err != nil {","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/doctor/fix/common.go#L99-L135","documentation":"After joining and re-relativizing, safeWorkspacePath could not compute filepath.Rel(absRoot, joined). In practice this is nearly unreachable: since joined is built from absRoot via Join, Rel always succeeds on the same platform. It is a defensive wrap of the Rel error (can occur on cross-volume path computation on some platforms).","triggerScenarios":"filepath.Rel(absRoot, joined) returning an error — theoretically possible only with mismatched path forms across volumes; the joined value here is derived from absRoot, so this is a defensive branch.","commonSituations":"Rare; encountered only if the Go runtime/platform behaves unexpectedly or code is modified to pass arbitrary pre-joined paths.","solutions":["Retry after confirming root and relPath are plain native-platform paths (no mixed separators or volume prefixes)","Report as a bug if reproducible: joined is constructed from absRoot, so Rel should never fail","Ensure the code is not modified to bypass the Join step with externally supplied joined paths","Update Go toolchain if a stdlib path bug is suspected"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if filepath.IsAbs(root) && filepath.Clean(rel) != rel {\n    rel = filepath.Clean(rel)\n}","typeGuard":null,"tryCatchPattern":"p, err := safeWorkspacePath(root, rel)\nif err != nil {\n    if strings.HasPrefix(err.Error(), \"failed to resolve path\") {\n        // defensive branch; report as a bug with the inputs\n    }\n    return err\n}","preventionTips":["Keep root and relPath as plain native-platform paths","Do not modify the helper to bypass the Join step","Treat occurrence as a bug report trigger"],"tags":["go","path-resolution","defensive"],"backgroundTag":"path-resolution-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}