plandex-ai/plandex · error

error creating convo message descriptions dir: %v

Error message

error creating convo message descriptions dir: %v

What it means

StoreDescription persists a convo message description as a JSON file under a per-plan directory. Before writing files it calls os.MkdirAll to create the descriptions directory; if the OS refuses (permissions, path issues, not a directory), the failure is wrapped with this message.

Source

Thrown at app/server/db/plan_helpers.go:315

}

func IncNumNonDraftPlans(userId string, tx *sqlx.Tx) error {
	_, err := tx.Exec("UPDATE users SET num_non_draft_plans = num_non_draft_plans + 1 WHERE id = $1", userId)

	if err != nil {
		return fmt.Errorf("error updating user num_non_draft_plans: %v", err)
	}

	return nil
}

func StoreDescription(description *ConvoMessageDescription) error {
	descriptionsDir := getPlanDescriptionsDir(description.OrgId, description.PlanId)

	err := os.MkdirAll(descriptionsDir, os.ModePerm)

	if err != nil {
		return fmt.Errorf("error creating convo message descriptions dir: %v", err)
	}

	for _, op := range description.Operations {
		if op.Content != "" {
			quoted := strconv.Quote(op.Content)
			op.Content = quoted[1 : len(quoted)-1]
		}
		if op.Description != "" {
			quoted := strconv.Quote(op.Description)
			op.Description = quoted[1 : len(quoted)-1]
		}
	}

	now := time.Now()

	if description.Id == "" {
		description.Id = uuid.New().String()
		description.CreatedAt = now

View on GitHub (pinned to e2d772072e)

Solutions

  1. Check OS permissions on the parent directory of the descriptions dir
  2. Confirm no regular file exists at any path component of descriptionsDir
  3. Verify the storage volume is mounted read-write in the deployment
  4. Ensure OrgId/PlanId values do not introduce illegal path characters
  5. Pre-create the base data directory with correct ownership at deploy time

Example fix

// before
descriptionsDir := getPlanDescriptionsDir(description.OrgId, description.PlanId)
err := os.MkdirAll(descriptionsDir, os.ModePerm)
if err != nil {
    return fmt.Errorf("error creating convo message descriptions dir: %v", err)
}
// after
descriptionsDir := getPlanDescriptionsDir(description.OrgId, description.PlanId)
if err := os.MkdirAll(descriptionsDir, 0o755); err != nil {
    return fmt.Errorf("error creating convo message descriptions dir %s: %w", descriptionsDir, err)
}
Defensive patterns

Strategy: validation

Validate before calling

if fi, err := os.Stat(filepath.Dir(descriptionsDir)); err == nil && !fi.IsDir() {
    return fmt.Errorf("%s exists and is not a directory", filepath.Dir(descriptionsDir))
}

Try / catch

if err := StoreDescription(desc); err != nil {
    if errors.Is(err, os.ErrPermission) {
        // alert: storage volume permissions wrong
    }
    return err
}

Prevention

When it happens

Trigger: os.MkdirAll(descriptionsDir, os.ModePerm) returns an error: parent path component is a regular file, permission denied on the storage volume, disk-full can surface here in some filesystems, or an invalid path built from OrgId/PlanId.

Common situations: Deployments where the app runs as a non-root user without write access to the data directory; volume mounted read-only; a file accidentally created at the same path as the expected directory; container missing the persistent volume mount.

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/62d866368ce25054. Report an issue: GitHub.