{"record":{"id":"c0ab0056afe535c7","repo":"kovidgoyal/kitty","slug":"abs-base-w","errorCode":null,"errorMessage":"abs base: %w","messagePattern":"abs base: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tools/utils/paths.go","lineNumber":358,"sourceCode":"//\n// Notes:\n//   - This uses filepath.Rel and then checks for leading \"..\" components to determine\n//     whether the returned relative path escapes the base directory.\n//   - On Windows behaviour is consistent with filepath semantics.\nfunc RelativeIfUnder(base, target string, resolveSymlinks bool) (rel string, inside bool, err error) {\n\t// Optionally resolve symlinks first\n\tif resolveSymlinks {\n\t\tif base, err = filepath.EvalSymlinks(base); err != nil {\n\t\t\treturn \"\", false, fmt.Errorf(\"resolving base symlinks: %w\", err)\n\t\t}\n\t\tif target, err = filepath.EvalSymlinks(target); err != nil {\n\t\t\treturn \"\", false, fmt.Errorf(\"resolving target symlinks: %w\", err)\n\t\t}\n\t}\n\n\t// Make absolute and clean\n\tif base, err = filepath.Abs(base); err != nil {\n\t\treturn \"\", false, fmt.Errorf(\"abs base: %w\", err)\n\t}\n\tif target, err = filepath.Abs(target); err != nil {\n\t\treturn \"\", false, fmt.Errorf(\"abs target: %w\", err)\n\t}\n\n\t// On Windows the volume (drive letter) must match. If they don't, the path is not inside.\n\tif runtime.GOOS == \"windows\" {\n\t\tif !strings.EqualFold(filepath.VolumeName(base), filepath.VolumeName(target)) {\n\t\t\treturn \"\", false, nil\n\t\t}\n\t}\n\n\t// Get the relative path from base to target\n\trel, err = filepath.Rel(base, target)\n\tif err != nil {\n\t\treturn \"\", false, fmt.Errorf(\"computing relative path: %w\", err)\n\t}\n","sourceCodeStart":340,"sourceCodeEnd":376,"githubUrl":"https://github.com/kovidgoyal/kitty/blob/6d5d0c440603ad9bdf6dcd599f73f6dde21acb44/tools/utils/paths.go#L340-L376","documentation":"RelativeIfUnder makes the base path absolute via filepath.Abs before comparing. Abs only fails when filepath.Abs itself errors — in practice when the current working directory cannot be determined (os.Getwd fails), since Abs of a relative base needs the CWD. This error wraps that failure.","triggerScenarios":"Calling with a relative base path from a process whose CWD has been deleted (e.g. the directory the tool was launched from was rm -rf'd), or in environments where getwd is disallowed.","commonSituations":"Long-running daemons/sessions whose startup directory was removed; shell in a deleted directory then invoking the tool with a relative base like \".\".","solutions":["Always pass an absolute base path (build it once at startup).","If using \".\", resolve it to an absolute path before the directory can disappear.","Restart the tool from an existing directory if the CWD was deleted.","Check errors from os.Getwd at startup and fail fast with a clear message."],"exampleFix":"// before\nrel, inside, err := utils.RelativeIfUnder(\".\", target, false)\n// after\nbase, _ := filepath.Abs(\".\") // captured at startup\nrel, inside, err := utils.RelativeIfUnder(base, target, false)","handlingStrategy":"validation","validationCode":"if !filepath.IsAbs(base) {\n    if abs, err := filepath.Abs(base); err == nil {\n        base = abs\n    } else {\n        return err // CWD unavailable\n    }\n}","typeGuard":"func cwdAvailable() bool {\n    wd, err := os.Getwd()\n    return err == nil && wd != \"\"\n}","tryCatchPattern":"rel, inside, err := utils.RelativeIfUnder(base, target, false)\nif err != nil {\n    if _, gerr := os.Getwd(); gerr != nil {\n        return fmt.Errorf(\"working directory lost; pass absolute paths: %w\", err)\n    }\n}","preventionTips":["Normalize base to an absolute path at process start.","Check os.Getwd at startup and fail fast.","Never rely on a CWD surviving long-lived processes."],"tags":["go","filesystem","cwd","paths"],"backgroundTag":"path-resolution-failed","analyzedSha":"6d5d0c440603ad9bdf6dcd599f73f6dde21acb44","analyzedAt":"2026-08-27T14:20:20.142Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}