plandex-ai/plandex · error
error reading convo file: %v
Error message
error reading convo file: %v
What it means
A worker goroutine failed to read one of the per-message JSON files in the plan convo directory via os.ReadFile. The error is sent to errCh and surfaced by GetPlanConvo wrapped as 'error reading convo files'. Unlike a missing whole directory, each individual file is expected to exist once ReadDir listed it, so this usually signals a race (file deleted mid-read) or permission problem.
Source
Thrown at app/server/db/convo_helpers.go:50
return nil, fmt.Errorf("error reading convo dir: %v", err)
}
errCh := make(chan error, len(files))
convoCh := make(chan *ConvoMessage, len(files))
for _, file := range files {
go func(file os.DirEntry) {
defer func() {
if r := recover(); r != nil {
log.Printf("panic in GetPlanConvo: %v\n%s", r, debug.Stack())
errCh <- fmt.Errorf("panic in GetPlanConvo: %v\n%s", r, debug.Stack())
runtime.Goexit() // don't allow outer function to continue and double-send to channel
}
}()
bytes, err := os.ReadFile(filepath.Join(convoDir, file.Name()))
if err != nil {
errCh <- fmt.Errorf("error reading convo file: %v", err)
return
}
var convoMessage ConvoMessage
err = json.Unmarshal(bytes, &convoMessage)
if err != nil {
errCh <- fmt.Errorf("error unmarshalling convo file: %v", err)
return
}
convoCh <- &convoMessage
}(file)
}
for i := 0; i < len(files); i++ {
select {View on GitHub (pinned to e2d772072e)
Solutions
- Check whether another process/script is deleting files from the convo dir concurrently and stop it or serialize access
- Verify file ownership/permissions in the convo dir (ls -l) and fix with chown/chmod
- Remove non-regular entries (symlinks, temp files) from the convo dir
- Ensure only one Plandex server instance uses the same data directory
- Retry the request — if transient (deleted mid-read), it may succeed after cleanup settles
Example fix
// skip entries that are not regular files
// before
for _, file := range files {
go func(file os.DirEntry) {
// after
for _, file := range files {
if !file.Type().IsRegular() {
continue
}
go func(file os.DirEntry) { Defensive patterns
Strategy: retry
Validate before calling
for _, f := range mustListDir(convoDir) {
if _, err := os.Stat(filepath.Join(convoDir, f.Name())); err != nil {
log.Printf("convo file vanished between list and read: %s", f.Name())
}
} Type guard
func isRetryableReadErr(err error) bool {
return errors.Is(err, os.ErrPermission) || errors.Is(err, syscall.EIO) || strings.Contains(err.Error(), "no such file")
} Try / catch
var convo []*db.ConvoMessage
var err error
for i := 0; i < 3; i++ {
convo, err = db.GetPlanConvo(orgId, planId)
if err == nil || !isRetryableReadErr(err) {
break
}
time.Sleep(100 * time.Millisecond << i)
} Prevention
- Run exactly one server instance per data directory
- Exclude the plans data dir from external cleanup jobs
- Restore files with correct ownership after backups
- Keep the convo dir free of symlinks and non-regular files
When it happens
Trigger: os.ReadFile(filepath.Join(convoDir, file.Name())) returns an error: the file was deleted between ReadDir and ReadFile (concurrent cleanup, plan deletion), permissions deny read, the entry is a broken symlink or special file, or name contains characters that break path resolution.
Common situations: Two server processes sharing one data dir where one deletes the plan; a cron/cleanup script purging old convo files while a user is viewing the convo; unreadable files after a restore with wrong ownership; non-regular files (sockets/temp files) accidentally placed in the convo dir.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- error reading settings-v2.json: %v
- failed to seek in temporary file: %w
- error reading convo dir: %v
- error reading convo message: %v
- error creating convo message descriptions dir: %v
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/d318d346061f2c30.
Report an issue: GitHub.