{"record":{"id":"3ad31decc053ed4f","repo":"kovidgoyal/kitty","slug":"resolving-target-symlinks-w","errorCode":null,"errorMessage":"resolving target symlinks: %w","messagePattern":"resolving target symlinks: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tools/utils/paths.go","lineNumber":352,"sourceCode":"// RelativeIfUnder returns the path to 'target' relative to 'base' if and only if\n// target is inside base. It returns the relative path, a boolean indicating\n// whether target is inside base, and an error.\n//\n// If resolveSymlinks is true, both base and target are run through filepath.EvalSymlinks\n// before containment checks. If base == target the function returns \".\" and true.\n//\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","sourceCodeStart":334,"sourceCodeEnd":370,"githubUrl":"https://github.com/kovidgoyal/kitty/blob/6d5d0c440603ad9bdf6dcd599f73f6dde21acb44/tools/utils/paths.go#L334-L370","documentation":"RelativeIfUnder with resolveSymlinks=true calls filepath.EvalSymlinks on both paths. This error means the target path could not be resolved: it does not exist, is a dangling symlink, has a symlink loop, or a component is not readable. The wrapped error carries the underlying *PathError cause.","triggerScenarios":"Passing a target that is a dangling symlink or a not-yet-created file with resolveSymlinks=true; symlink cycles; EACCES on a path component.","commonSituations":"Comparing a planned output file path against a base directory before the file exists; symlinked home directories on macOS; NFS stale handles.","solutions":["Create or touch the target file first, or resolve an existing ancestor directory instead.","Repair the dangling symlink (ls -l to inspect, then relink or remove).","Use resolveSymlinks=false when the target may legitimately not exist yet.","Inspect the wrapped error with errors.Unwrap to distinguish ENOENT/ELOOP/EACCES."],"exampleFix":"// before\nrel, inside, err := utils.RelativeIfUnder(base, target, true)\n// after\nrel, inside, err := utils.RelativeIfUnder(base, target, false)","handlingStrategy":"fallback","validationCode":"if _, err := os.Lstat(target); err != nil {\n    // target missing/dangling; either create it or skip resolution\n}","typeGuard":"func targetResolvable(target string) bool {\n    _, err := filepath.EvalSymlinks(target)\n    return err == nil\n}","tryCatchPattern":"rel, inside, err := utils.RelativeIfUnder(base, target, true)\nif err != nil {\n    rel, inside, err = utils.RelativeIfUnder(base, target, false)\n    if err != nil { return err }\n}","preventionTips":["Pass resolveSymlinks=false for paths that may not exist yet.","Resolve an existing ancestor (filepath.Dir) instead of the future file.","Inspect errors.Unwrap to distinguish ENOENT vs ELOOP vs EACCES."],"tags":["go","filesystem","symlink","paths"],"backgroundTag":"path-resolution-failed","analyzedSha":"6d5d0c440603ad9bdf6dcd599f73f6dde21acb44","analyzedAt":"2026-08-27T14:20:20.142Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}