gastownhall/beads · error

failed to create .beads directory: %w

Error message

failed to create .beads directory: %w

What it means

EnsureFile resolves the audit file path via Path(), then ensures the .beads directory exists with os.MkdirAll(dir, 0700). If the mkdir fails, the error is wrapped with 'failed to create .beads directory'. This means the audit sidecar cannot be created because its parent directory cannot be materialized.

Source

Thrown at internal/audit/audit.go:90

}

func truthy(raw string) bool {
	switch strings.ToLower(strings.TrimSpace(raw)) {
	case "1", "t", "true", "y", "yes", "on":
		return true
	default:
		return false
	}
}

// EnsureFile creates .beads/interactions.jsonl if it does not exist.
func EnsureFile() (string, error) {
	p, err := Path()
	if err != nil {
		return "", err
	}
	if err := os.MkdirAll(filepath.Dir(p), 0700); err != nil {
		return "", fmt.Errorf("failed to create .beads directory: %w", err)
	}
	if ensureFileBeforeCreateHook != nil {
		ensureFileBeforeCreateHook(p)
	}
	f, err := os.OpenFile(p, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644) // nolint:gosec // JSONL is intended to be shared via git across clones/tools.
	if err == nil {
		if closeErr := f.Close(); closeErr != nil {
			return "", fmt.Errorf("failed to close interactions log: %w", closeErr)
		}
		return p, nil
	}
	if !errors.Is(err, os.ErrExist) {
		return "", fmt.Errorf("failed to create interactions log: %w", err)
	}
	return p, nil
}

// Append appends an event to .beads/interactions.jsonl as a single JSON line.

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check whether a file named .beads exists and remove/rename it so a directory can be created
  2. Grant write permission on the parent directory (chown/chmod) or run as the correct user
  3. If the volume is read-only, point the beads directory at a writable location

Example fix

// before
$ ls -la | grep beads
-rw-r--r--  .beads        # a file, not a directory
// after
$ rm .beads && bd init   # recreate .beads as a directory
Defensive patterns

Strategy: validation

Validate before calling

dir := filepath.Dir(auditPath)
if fi, err := os.Stat(dir); err == nil && !fi.IsDir() {
    return fmt.Errorf("%s exists as a file; remove it so a directory can be created", dir)
}
if err := os.MkdirAll(dir, 0700); err != nil { return err }

Try / catch

p, err := audit.EnsureFile()
if err != nil {
    if strings.Contains(err.Error(), "failed to create .beads directory") {
        return fmt.Errorf("check .beads is not a plain file and parent is writable: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: MkdirAll fails because a component of the path exists as a regular file, the parent is read-only, or the process lacks permission to create directories there.

Common situations: A stray file named '.beads' (not a directory) in the repo, read-only checkouts or mounted volumes, or running bd as a user without write access to the project or HOME.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/e1812479bae96bf0. Report an issue: GitHub.