gastownhall/beads · error

failed to create .beads directory: %w

Error message

failed to create .beads directory: %w

What it means

During `bd init`, migrateOldDatabases creates the .beads directory (mode 0750) before scanning for legacy *.db files to rename to beads.db. This error wraps the underlying os.MkdirAll failure, meaning the directory could not be created on disk. bd throws it because without .beads there is nowhere to place or discover the database, so initialization cannot proceed.

Source

Thrown at cmd/bd/init.go:2370

	{name: "pg-schema", usage: "Legacy PostgreSQL schema (removed backend compatibility only)", origin: "the removed PostgreSQL/MySQL initialization paths", rationale: configfile.RemovedBackendRationale},
	{name: "mysql-url", usage: "Legacy MySQL connection URL (removed backend compatibility only)", origin: "the removed PostgreSQL/MySQL initialization paths", rationale: configfile.RemovedBackendRationale},
	{name: "mysql-database", usage: "Legacy MySQL database (removed backend compatibility only)", origin: "the removed PostgreSQL/MySQL initialization paths", rationale: configfile.RemovedBackendRationale},
	{name: "sqlite-path", usage: "Legacy SQLite database file (removed backend compatibility only)", origin: "the removed SQLite initialization path", rationale: configfile.RemovedSQLiteRationale},
}

// migrateOldDatabases detects and migrates old database files to beads.db
func migrateOldDatabases(targetPath string, quiet bool) error {
	targetDir := filepath.Dir(targetPath)
	targetName := filepath.Base(targetPath)

	// If target already exists, no migration needed
	if _, err := os.Stat(targetPath); err == nil {
		return nil
	}

	// Create .beads directory if it doesn't exist
	if err := os.MkdirAll(targetDir, 0750); err != nil {
		return fmt.Errorf("failed to create .beads directory: %w", err)
	}

	// Look for existing .db files in the .beads directory
	pattern := filepath.Join(targetDir, "*.db")
	matches, err := filepath.Glob(pattern)
	if err != nil {
		return fmt.Errorf("failed to search for existing databases: %w", err)
	}

	// Filter out the target file name and any backup files
	var oldDBs []string
	for _, match := range matches {
		baseName := filepath.Base(match)
		if baseName != targetName && !strings.HasSuffix(baseName, ".backup.db") {
			oldDBs = append(oldDBs, match)
		}
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check that the .beads path (or BEADS_DIR target) is not occupied by a non-directory file and remove/rename it.
  2. Verify write permissions on the repository root (or the BEADS_DIR parent) for the current user; chown/chmod as needed.
  3. If on a read-only mount or container layer, remount read-write or run bd from a writable location.
  4. Check disk space (df -h) and free space if the volume is full.

Example fix

// before: running in a read-only checkout
$ bd init
# failed to create .beads directory: mkdir .beads: read-only file system

// after: run from a writable workspace or remount
$ mount -o remount,rw /path/to/repo
$ bd init
Defensive patterns

Strategy: try-catch

Validate before calling

const st, err = os.Stat(beadsDir)
// In Go (caller preflight):
if fi, err := os.Stat(filepath.Dir(targetPath)); err == nil && !fi.IsDir() {
    return fmt.Errorf("%s exists and is not a directory", filepath.Dir(targetPath))
}
if err := unix.Access(repoRoot, unix.W_OK); err != nil {
    return fmt.Errorf("repo root not writable: %v", err)
}

Try / catch

if err := migrateOldDatabases(targetPath, quiet); err != nil {
    var pe *fs.PathError
    if errors.As(err, &pe) && (errors.Is(pe.Err, syscall.EACCES) || errors.Is(pe.Err, syscall.EROFS)) {
        // surface a permissions/read-only hint before retrying
    }
    return err
}

Prevention

When it happens

Trigger: Running `bd init` (or a path that calls migrateOldDatabases) when os.MkdirAll(targetDir, 0750) fails — e.g. the parent directory does not exist and cannot be created, the filesystem is read-only, or a non-directory file already exists at the .beads path.

Common situations: Mounting the repo on a read-only volume or read-only container layer; a stale regular file named .beads blocking creation; running bd as a user without write permission on the repository root; BEADS_DIR pointing at an unwritable path; disk full.

Related errors


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