{"record":{"id":"83e77e56872c6d83","repo":"charmbracelet/crush","slug":"failed-to-read-file-w-83e77e","errorCode":null,"errorMessage":"failed to read file: %w","messagePattern":"failed to read file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/agent/tools/lsp_replace_symbol.go","lineNumber":97,"sourceCode":"\t\t\tif client == nil {\n\t\t\t\treturn fantasy.NewTextErrorResponse(fmt.Sprintf(\"no LSP client handles file: %s\", params.FilePath)), nil\n\t\t\t}\n\n\t\t\tsymbols, err := client.DocumentSymbols(ctx, params.FilePath)\n\t\t\tif err != nil {\n\t\t\t\treturn fantasy.NewTextErrorResponse(fmt.Sprintf(\"failed to get document symbols: %s\", err)), nil\n\t\t\t}\n\n\t\t\ttarget := findSymbolByName(symbols, params.Symbol)\n\t\t\tif target == nil {\n\t\t\t\treturn fantasy.NewTextErrorResponse(fmt.Sprintf(\"symbol '%s' not found in %s\", params.Symbol, params.FilePath)), nil\n\t\t\t}\n\n\t\t\trng := target.GetRange()\n\n\t\t\tcontent, err := os.ReadFile(params.FilePath)\n\t\t\tif err != nil {\n\t\t\t\treturn fantasy.ToolResponse{}, fmt.Errorf(\"failed to read file: %w\", err)\n\t\t\t}\n\n\t\t\tlines := strings.Split(string(content), \"\\n\")\n\t\t\tstartLine := int(rng.Start.Line)\n\t\t\tendLine := int(rng.End.Line)\n\t\t\tif startLine >= len(lines) || endLine >= len(lines) {\n\t\t\t\treturn fantasy.NewTextErrorResponse(\"symbol range exceeds file length\"), nil\n\t\t\t}\n\n\t\t\t// Compute new content before permission so the dialog can show a diff.\n\t\t\tvar newLines []string\n\t\t\tswitch action {\n\t\t\tcase \"replace\":\n\t\t\t\tnewLines = make([]string, 0, len(lines))\n\t\t\t\tnewLines = append(newLines, lines[:startLine]...)\n\t\t\t\tnewLines = append(newLines, strings.Split(params.Replacement, \"\\n\")...)\n\t\t\t\tnewLines = append(newLines, lines[endLine+1:]...)\n\t\t\tcase \"add_before\":","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/agent/tools/lsp_replace_symbol.go#L79-L115","documentation":"This error is returned by the lsp_replace_symbol tool when os.ReadFile cannot read the target file at params.FilePath. The LSP located the symbol and computed its range, but the on-disk file could not be read, so the tool aborts before performing the replacement. The wrapped OS error (%w) tells the real cause: missing file, permissions, or a path that is not a regular file.","triggerScenarios":"Calling the lsp_replace_symbol tool with a FilePath that does not exist, has been deleted after LSP analysis, is a directory, or is unreadable due to file permissions (or the process lacks read access, e.g. root-owned file).","commonSituations":"Symbol reference resolved against a stale index after the file was deleted/renamed; relative path passed where an absolute path is expected; running crush in a container/sandbox where the file is not mounted; file permissions changed by another process.","solutions":["Verify the file exists and is readable: run ls -l on params.FilePath and check the path is absolute and correct.","Re-run the tool after refreshing state so the LSP re-resolves the symbol against the current filesystem.","Fix file permissions (chmod) or run as a user with read access to the file.","If the file was deleted or moved, restore it or update the symbol location."],"exampleFix":"// before\ncontent, err := os.ReadFile(params.FilePath)\nif err != nil {\n\treturn fantasy.ToolResponse{}, fmt.Errorf(\"failed to read file: %w\", err)\n}\n// after\nif _, statErr := os.Stat(params.FilePath); statErr != nil {\n\treturn fantasy.ToolResponse{}, fmt.Errorf(\"file not found before read: %w\", statErr)\n}\ncontent, err := os.ReadFile(params.FilePath)\nif err != nil {\n\treturn fantasy.ToolResponse{}, fmt.Errorf(\"failed to read file: %w\", err)\n}","handlingStrategy":"validation","validationCode":"if info, err := os.Stat(filePath); err != nil || info.IsDir() {\n\treturn fmt.Errorf(\"cannot replace symbol: file %s unreadable: %w\", filePath, err)\n}","typeGuard":null,"tryCatchPattern":"content, err := os.ReadFile(path)\nif err != nil {\n\tvar perr *fs.PathError\n\tif errors.As(err, &perr) && errors.Is(err, fs.ErrNotExist) {\n\t\t// handle missing file: refresh LSP index or skip\n\t}\n\treturn err\n}","preventionTips":["Always pass absolute paths to symbol-replacement tools.","Re-resolve symbol locations against the current filesystem before editing.","Check file readability (os.Stat + permissions) before invoking LSP edit tools.","Avoid editing files inside read-only or unmounted paths."],"tags":["filesystem","go","lsp","file-read"],"backgroundTag":"file-not-found","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}