gastownhall/beads · error

failed to create beads directory %s: %w

Error message

failed to create beads directory %s: %w

What it means

Before writing the credential key file, initCredentialKey ensures the .beads directory exists via os.MkdirAll(s.beadsDir, 0700). This error wraps a failure of that directory creation, meaning bd could not create the directory that must hold the encryption key. It commonly surfaces when connecting to an external server without having run `bd init` (GH#2641) and the parent path is not creatable.

Source

Thrown at internal/storage/dolt/credentials.go:100

		}
	}

	// Generate new random 32-byte key (AES-256)
	key = make([]byte, 32)
	if _, err := io.ReadFull(rand.Reader, key); err != nil {
		return fmt.Errorf("failed to generate credential encryption key: %w", err)
	}

	// Migrate existing credentials from old dbPath-derived key to new random key
	if err := s.migrateCredentialKeys(ctx, key); err != nil {
		return fmt.Errorf("failed to migrate credential keys: %w", err)
	}

	// Write key file with owner-only permissions (0600).
	// Ensure the directory exists first — when connecting to an external
	// server without having run `bd init`, .beads/ may not exist yet (GH#2641).
	if err := os.MkdirAll(s.beadsDir, 0700); err != nil {
		return fmt.Errorf("failed to create beads directory %s: %w", s.beadsDir, err)
	}
	if err := os.WriteFile(keyPath, key, 0600); err != nil {
		return fmt.Errorf("failed to write credential key file: %w", err)
	}

	s.credentialKey = key
	return nil
}

// ensureCredentialKey lazily initializes the credential key when federation
// operations actually need password encryption or decryption.
func (s *DoltStore) ensureCredentialKey(ctx context.Context) error {
	s.mu.RLock()
	if s.credentialKey != nil {
		s.mu.RUnlock()
		return nil
	}
	s.mu.RUnlock()

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check that the directory at the reported path can be created: verify write permission on its parent (ls -ld <parent>)
  2. If a regular file named .beads exists, remove or rename it so the directory can be created
  3. Create the directory manually: mkdir -p .beads (or run `bd init` first)
  4. If the workspace is intentionally read-only, run bd from a writable workspace or point it at a writable location

Example fix

// before
$ bd sync  # fails: failed to create beads directory /ro-workspace/.beads: mkdir ...: read-only file system
// after
$ chmod u+w /ro-workspace && bd init   # or: mkdir -p /ro-workspace/.beads
Defensive patterns

Strategy: validation

Validate before calling

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

Prevention

When it happens

Trigger: os.MkdirAll(s.beadsDir, 0700) fails during initCredentialKey: the .beads directory (or an ancestor) cannot be created because a parent is missing on a read-only filesystem, permission is denied, the path exists as a regular file, or the workspace root is on a read-only mount.

Common situations: Connecting to an external dolt-sql-server from a directory where .beads/ was never initialized and the cwd is read-only or unwritable; a file named .beads exists where the directory should be; running as a different user than the workspace owner; container images with read-only workdirs.

Related errors


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