chenhg5/cc-connect · error
gemini: read chats dir: %w
Error message
gemini: read chats dir: %w
What it means
Reading ~/.gemini/tmp/<slug>/chats failed with an error other than NotExist (which is treated as an empty list). The wrapped error is returned from listGeminiSessions → ListSessions. This means the directory exists but is unreadable, or another I/O error occurred.
Source
Thrown at agent/gemini/gemini.go:520
}
return ""
}
func listGeminiSessions(workDir string) ([]core.AgentSessionInfo, error) {
homeDir, err := os.UserHomeDir()
if err != nil {
return nil, fmt.Errorf("gemini: cannot determine home dir: %w", err)
}
slug := geminiProjectSlug(workDir)
chatsDir := filepath.Join(homeDir, ".gemini", "tmp", slug, "chats")
entries, err := os.ReadDir(chatsDir)
if err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, fmt.Errorf("gemini: read chats dir: %w", err)
}
var sessions []core.AgentSessionInfo
for _, entry := range entries {
if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".json") {
continue
}
data, err := os.ReadFile(filepath.Join(chatsDir, entry.Name()))
if err != nil {
continue
}
var sf sessionFile
if json.Unmarshal(data, &sf) != nil || sf.SessionID == "" {
continue
}
View on GitHub (pinned to 4000b2338a)
Solutions
- Check `ls -la ~/.gemini/tmp/<slug>/chats` — fix permissions (chmod/chown) or remove a stray file that shadows the directory
- If the home dir is read-only, mount it writable or relocate HOME
- Inspect the wrapped inner error (`gemini: read chats dir: ...`) for the exact errno
- Restore ~/.gemini from a known-good state or let the gemini CLI recreate it
Example fix
// before $ ls ~/.gemini/tmp/myproj/chats ls: cannot open 'chats': Permission denied // after $ chmod 755 ~/.gemini ~/.gemini/tmp ~/.gemini/tmp/myproj/chats $ sudo chown -R $USER ~/.gemini
Defensive patterns
Strategy: try-catch
Validate before calling
chats := filepath.Join(os.Getenv("HOME"), ".gemini", "tmp", slug, "chats")
if fi, err := os.Stat(chats); err == nil && !fi.IsDir() {
return fmt.Errorf("%s exists but is not a directory", chats)
} Try / catch
sessions, err := agent.ListSessions(ctx)
if err != nil && strings.Contains(err.Error(), "read chats dir") {
var pe *fs.PathError
if errors.As(err, &pe) { log.Printf("fs error on %s: %v", pe.Path, pe.Err) }
} Prevention
- Keep ~/.gemini owned and writable by the service user
- Avoid sync/backup tools replacing ~/.gemini with partial copies
- Stat the chats dir at startup to catch permission drift early
When it happens
Trigger: os.ReadDir returns e.g. EACCES (permissions changed on ~/.gemini or ~/.gemini/tmp), ENOTDIR (a file named `chats` or an intermediate component replaced the directory), or the path is a symlink to an unreadable target — anything not os.IsNotExist.
Common situations: Backup/sync tool replaced ~/.gemini with a partial copy; permissions tightened by security tooling; ~/.gemini/tmp/<slug>/chats created as a regular file by a buggy script; read-only mounted home.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- read existing Agy hooks %s: %w
- claudecode: create usage temp dir: %w
- claudecode: chmod per-spawn prompt file 0o644: %w
- codex app-server: create image dir: %w
- codex: mkdir codex home: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/69b1e4723040de8d.
Report an issue: GitHub.