plandex-ai/plandex · error
error creating convo dir: %v
Error message
error creating convo dir: %v
What it means
After marshalling, StoreConvoMessage ensures the plan's convo directory exists with os.MkdirAll (perm os.ModePerm). This error wraps the MkdirAll failure, meaning the directory (and any missing parents) could not be created and the message was not persisted.
Source
Thrown at app/server/db/convo_helpers.go:122
ts := time.Now().UTC()
if message.Id == "" {
message.Id = uuid.New().String()
}
message.CreatedAt = ts
bytes, err := json.Marshal(message)
if err != nil {
return "", fmt.Errorf("error marshalling convo message: %v", err)
}
err = os.MkdirAll(convoDir, os.ModePerm)
if err != nil {
return "", fmt.Errorf("error creating convo dir: %v", err)
}
err = os.WriteFile(filepath.Join(convoDir, message.Id+".json"), bytes, os.ModePerm)
if err != nil {
return "", fmt.Errorf("error writing convo message: %v", err)
}
err = AddPlanConvoMessage(message, branch)
if err != nil {
return "", fmt.Errorf("error adding convo tokens: %v", err)
}
var desc string
if message.Role == openai.ChatMessageRoleUser {
desc = "💬 User prompt"
// TODO: add user nameView on GitHub (pinned to e2d772072e)
Solutions
- Check the wrapped *PathError: if EACCES/EPERM fix ownership/permissions on the parent data directory (chown/chmod)
- If ENOTDIR/EEXIST, remove the regular file occupying the convoDir path and let MkdirAll recreate it
- Verify the data volume is mounted read-write (mount | grep, or container volume config)
- Free disk space if the error indicates ENOSPC
- Confirm the configured data-dir root exists and is writable by the server process
Example fix
// before mount -o ro /dev/sdb /plandex-data // after mount -o remount,rw /plandex-data chown -R plandex:plandex /plandex-data/plans
Defensive patterns
Strategy: validation
Validate before calling
parent := filepath.Dir(getPlanConversationDir(orgId, planId))
if info, err := os.Stat(parent); err != nil || !info.IsDir() {
return fmt.Errorf("plans data dir missing or not a directory: %s", parent)
}
if err := syscall.Access(parent, os.O_WRONLY); err != nil {
return fmt.Errorf("data dir not writable: %w", err)
} Type guard
func isMkdirPathError(err error) (*fs.PathError, bool) {
var pe *fs.PathError
return pe, errors.As(err, &pe) && pe.Op == "mkdir"
} Try / catch
id, err := db.StoreConvoMessage(repo, msg, userId, branch, false)
if err != nil {
if strings.Contains(err.Error(), "creating convo dir") {
// check mount is rw and ownership, then retry once
if isVolumeReadOnly() { remountRW() }
id, err = db.StoreConvoMessage(repo, msg, userId, branch, false)
}
return err
} Prevention
- Ensure the data volume is mounted read-write in container/volume config
- Own the whole data dir with the server user
- Never create files where the app expects directories
- Alert on disk-full (ENOSPC) before it blocks message storage
When it happens
Trigger: os.MkdirAll(convoDir, os.ModePerm) fails: parent data-dir path missing on a read-only filesystem, permission denied on the parent directory, a regular file already exists at the convoDir path (MkdirAll returns ENOTDIR), path too long, or the volume is full/unavailable.
Common situations: Data volume mounted read-only after a container/storage change; data dir owned by another user (root after image rebuild); an operator accidentally created a file where the plan convo directory should be; disk full.
Understand the failure class
Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.
Related errors
- error walking directory: %s
- failed to check if %s exists: %s
- failed to read %s: %s
- failed to create directory %s: %s
- failed to write %s: %s
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/81aba6504caee89c.
Report an issue: GitHub.