plandex-ai/plandex · error
error reading descriptions dir: %v
Error message
error reading descriptions dir: %v
What it means
GetConvoMessageDescriptions reads a plan's descriptions directory with os.ReadDir. A missing directory is treated as empty (os.IsNotExist short-circuit), but any other ReadDir failure (permissions, not a directory, I/O error) is wrapped as 'error reading descriptions dir: %v' and returned, failing the whole descriptions load.
Source
Thrown at app/server/db/result_helpers.go:320
}
planState.CurrentPlanFiles = currentPlanFiles
return planState, nil
}
func GetConvoMessageDescriptions(orgId, planId string) ([]*ConvoMessageDescription, error) {
var descriptions []*ConvoMessageDescription
descriptionsDir := getPlanDescriptionsDir(orgId, planId)
files, err := os.ReadDir(descriptionsDir)
if err != nil {
if os.IsNotExist(err) {
return descriptions, nil
}
return nil, fmt.Errorf("error reading descriptions dir: %v", err)
}
errCh := make(chan error, len(files))
descCh := make(chan *ConvoMessageDescription, len(files))
for _, file := range files {
go func(file os.DirEntry) {
defer func() {
if r := recover(); r != nil {
log.Printf("panic in GetConvoMessageDescriptions: %v\n%s", r, debug.Stack())
errCh <- fmt.Errorf("panic in GetConvoMessageDescriptions: %v\n%s", r, debug.Stack())
runtime.Goexit() // don't allow outer function to continue and double-send to channel
}
}()
path := filepath.Join(descriptionsDir, file.Name())
bytes, err := os.ReadFile(path)
View on GitHub (pinned to e2d772072e)
Solutions
- Read the wrapped inner error (errno) to identify permission vs not-a-directory vs I/O
- Check permissions/ownership of the descriptions directory for the server process user
- Confirm getPlanDescriptionsDir(orgId, planId) resolves to the correct data-root path
- If the path is a file or symlink target is broken, fix or remove it and recreate the directory
- If the plan has no descriptions and the dir is genuinely absent, no fix is needed — the library returns an empty list
Example fix
// before
files, err := os.ReadDir(descriptionsDir)
if err != nil {
return nil, fmt.Errorf("error reading descriptions dir: %v", err)
}
// after
files, err := os.ReadDir(descriptionsDir)
if err != nil {
if os.IsNotExist(err) || os.IsPermission(err) {
return descriptions, nil // treat unreadable/missing dir as no descriptions
}
return nil, fmt.Errorf("error reading descriptions dir: %v", err)
} Defensive patterns
Strategy: validation
Validate before calling
func descriptionsDirReadable(orgId, planId string) error {
dir := getPlanDescriptionsDir(orgId, planId)
info, err := os.Stat(dir)
if os.IsNotExist(err) {
return nil // treated as empty by the library
}
if err != nil {
return err
}
if !info.IsDir() {
return fmt.Errorf("%s is not a directory", dir)
}
f, err := os.Open(dir)
if err != nil {
return err
}
return f.Close()
} Type guard
func isDescriptionsDirError(err error) bool {
return err != nil && strings.Contains(err.Error(), "error reading descriptions dir")
} Try / catch
descriptions, err := GetConvoMessageDescriptions(orgId, planId)
if err != nil {
if isDescriptionsDirError(err) {
log.Printf("descriptions dir unreadable, treating as empty: %v", err)
descriptions = nil
} else {
return nil, err
}
} Prevention
- Check the data-root path configuration after any deployment or volume move
- Ensure the directory is a directory, not a file or symlink to a file
- Keep server process user ownership consistent on the plan data root
- Remember: a missing dir is fine (returns empty); only other errors are fatal
When it happens
Trigger: Calling GetConvoMessageDescriptions (directly or via GetCurrentPlanState / ClearContext / PendingBuildsByPath / invalidateConflictedResults) when descriptionsDir exists but cannot be listed: wrong permissions, path is a file not a directory, or an I/O error during listing.
Common situations: Server run under a different user than the one that created plan data (permission denied); getPlanDescriptionsDir path misconfigured after a data-root move so it points at a regular file; NFS/overlay filesystem returning EIO; symlink loops.
Related errors
- error walking directory: %s
- failed to check if %s exists: %s
- failed to read %s: %s
- failed to write %s: %s
- failed to remove %s: %s
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/76fee0dddef50e23.
Report an issue: GitHub.