{"record":{"id":"a2470c363ef1e8e1","repo":"alibaba/open-code-review","slug":"read-sessions-dir-q-w","errorCode":null,"errorMessage":"read sessions dir %q: %w","messagePattern":"read sessions dir %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/session/list.go","lineNumber":119,"sourceCode":"\t\treturn \"\", fmt.Errorf(\"resolve home dir: %w\", err)\n\t}\n\treturn filepath.Join(home, \".opencodereview\", sessionSubDir, encodeRepoPath(repoDir)), nil\n}\n\n// ListSessions enumerates all persisted sessions for the given repository\n// directory, sorted by StartTime descending (most recent first). Missing\n// directories return an empty slice with no error.\nfunc ListSessions(repoDir string) ([]Summary, error) {\n\tdir, err := SessionsDir(repoDir)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tentries, err := os.ReadDir(dir)\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn nil, fmt.Errorf(\"read sessions dir %q: %w\", dir, err)\n\t}\n\tsummaries := make([]Summary, 0, len(entries))\n\tfor _, entry := range entries {\n\t\tname := entry.Name()\n\t\tif entry.IsDir() || !strings.HasSuffix(name, \".jsonl\") {\n\t\t\tcontinue\n\t\t}\n\t\tsessionID := strings.TrimSuffix(name, \".jsonl\")\n\t\tsummary, err := loadSummaryFromFile(filepath.Join(dir, name), sessionID, repoDir)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tsummaries = append(summaries, *summary)\n\t}\n\tsort.Slice(summaries, func(i, j int) bool {\n\t\treturn summaries[i].StartTime.After(summaries[j].StartTime)\n\t})\n\treturn summaries, nil","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/internal/session/list.go#L101-L137","documentation":"ListSessions reads the per-repo sessions directory and, if os.ReadDir fails with anything other than NotExist (which yields an empty list), wraps it as 'read sessions dir %q: ...'. This means the sessions directory exists but cannot be read, or another OS error occurred.","triggerScenarios":"Calling ListSessions (or runSessionList/completeSessionIDs) when the sessions dir exists but is unreadable — or is actually a file, or has permission issues. A missing dir returns (nil, nil) and does NOT produce this error.","commonSituations":"~/.opencodereview/sessions/<repo> created as a regular file by accident; ownership changed (different user ran before); permissions tightened by security policy; NFS mount stale.","solutions":["ls -la ~/.opencodereview/sessions/ — if the repo path is a file, remove or rename it.","Fix permissions: chown/chmod the sessions directory so the current user can read it.","Check for mount/stale-handle issues if the directory lives on a network filesystem.","Read the wrapped cause (%w) for the exact errno (EACCES, ENOTDIR, etc.)."],"exampleFix":"// before\n$ ls -la ~/.opencodereview/sessions/\n-rw-r--r--  repo-abc123   (file where dir should be)\n// after\nrm ~/.opencodereview/sessions/repo-abc123\nocr session list","handlingStrategy":"try-catch","validationCode":"dir, err := session.SessionsDir(repoDir)\nif err != nil {\n    return err\n}\nif fi, err := os.Stat(dir); err == nil && !fi.IsDir() {\n    return fmt.Errorf(\"%s is a file, not a directory\", dir)\n}","typeGuard":null,"tryCatchPattern":"sessions, err := session.ListSessions(repoDir)\nif err != nil {\n    if strings.Contains(err.Error(), \"read sessions dir\") {\n        // permission/ENOTDIR issue: attempt repair or degrade gracefully\n        log.Warnf(\"cannot read sessions: %v\", err)\n        return nil\n    }\n    return err\n}","preventionTips":["Never create files where ~/.opencodereview/sessions/<repo> directories belong.","Keep consistent user ownership of the sessions tree.","Remember NotExist is normal (first run) — only other errors matter.","Check mounts/permissions if sessions live on network storage."],"tags":["session","filesystem","permissions"],"backgroundTag":"directory-not-readable","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}