{"record":{"id":"97896bf1a28d87eb","repo":"charmbracelet/crush","slug":"path-does-not-exist-s","errorCode":null,"errorMessage":"path does not exist: %s","messagePattern":"path does not exist: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/agent/tools/ls.go","lineNumber":140,"sourceCode":"\t\t\t\t}\n\t\t\t}\n\n\t\t\toutput, metadata, err := ListDirectoryTree(searchPath, params, lsConfig)\n\t\t\tif err != nil {\n\t\t\t\treturn fantasy.NewTextErrorResponse(err.Error()), nil\n\t\t\t}\n\n\t\t\treturn fantasy.WithResponseMetadata(\n\t\t\t\tfantasy.NewTextResponse(output),\n\t\t\t\tmetadata,\n\t\t\t), nil\n\t\t},\n\t)\n}\n\nfunc ListDirectoryTree(searchPath string, params LSParams, lsConfig config.ToolLs) (string, LSResponseMetadata, error) {\n\tif _, err := os.Stat(searchPath); os.IsNotExist(err) {\n\t\treturn \"\", LSResponseMetadata{}, fmt.Errorf(\"path does not exist: %s\", searchPath)\n\t}\n\n\tdepth, limit := lsConfig.Limits()\n\tmaxFiles := cmp.Or(limit, maxLSFiles)\n\tfiles, truncated, err := fsext.ListDirectory(\n\t\tsearchPath,\n\t\tparams.Ignore,\n\t\tcmp.Or(params.Depth, depth),\n\t\tmaxFiles,\n\t)\n\tif err != nil {\n\t\treturn \"\", LSResponseMetadata{}, fmt.Errorf(\"error listing directory: %w\", err)\n\t}\n\n\tmetadata := LSResponseMetadata{\n\t\tNumberOfFiles: len(files),\n\t\tTruncated:     truncated,\n\t}","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/agent/tools/ls.go#L122-L158","documentation":"ListDirectoryTree stats the searchPath before listing. If os.Stat reports the path does not exist, the tool returns 'path does not exist: <path>'. This is a preflight existence check distinct from read-permission or walk errors.","triggerScenarios":"Calling ListDirectoryTree (public API) with a typo'd path, a deleted directory, or a path that only exists after symlink resolution that fails.","commonSituations":"Stale paths after a branch switch or git clean, typos in absolute paths, or paths deleted concurrently between the model's decision and the tool call.","solutions":["Verify the path exists with os.Stat before calling.","Correct typos; use an absolute path derived from the working directory.","If the path may race with deletion, retry after re-checking existence."],"exampleFix":"// before\nListDirectoryTree(\"/proj/src\", params, cfg) // src was renamed to source\n// after\nListDirectoryTree(\"/proj/source\", params, cfg)","handlingStrategy":"validation","validationCode":"if _, err := os.Stat(searchPath); os.IsNotExist(err) {\n    return fmt.Errorf(\"path missing: %s\", searchPath)\n}","typeGuard":"func pathExists(p string) bool { _, err := os.Stat(p); return !os.IsNotExist(err) }","tryCatchPattern":"if err != nil {\n    if strings.Contains(err.Error(), \"path does not exist\") { /* correct path and retry */ }\n}","preventionTips":["Resolve relative paths against the working directory before calling","Re-check existence after git operations that may delete files","Use tab-completion or file listing to confirm exact paths"],"tags":["filesystem","path","not-found"],"backgroundTag":"path-not-found","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}