gastownhall/beads · error
fs: CreateBeadsDir: mkdir %s: %w
Error message
fs: CreateBeadsDir: mkdir %s: %w
What it means
This error wraps a failure from os.MkdirAll when creating the .beads directory. It is thrown by CreateBeadsDir when the directory cannot be created at the resolved beadsDir path (permissions, parent missing in a read-only tree, path is a file, etc.). The wrapped OS error (%w) carries the underlying cause.
Source
Thrown at internal/storage/domain/fs/beads.go:68
func (r *beadsDirFSRepositoryImpl) BeadsDirIsLocal(ctx context.Context) bool {
workDir := filepath.Clean(utils.CanonicalizePath(r.workDir))
beadsDir := filepath.Clean(utils.CanonicalizePath(r.beadsDir))
if beadsDir == workDir {
return true
}
rel, err := filepath.Rel(workDir, beadsDir)
if err != nil {
return false
}
return rel != ".." && !strings.HasPrefix(rel, ".."+string(filepath.Separator))
}
func (r *beadsDirFSRepositoryImpl) CreateBeadsDir(ctx context.Context) error {
if r.beadsDir == "" {
return fmt.Errorf("fs: CreateBeadsDir: beadsDir not resolved")
}
if err := os.MkdirAll(r.beadsDir, config.BeadsDirPerm); err != nil {
return fmt.Errorf("fs: CreateBeadsDir: mkdir %s: %w", r.beadsDir, err)
}
if _, err := config.FixBeadsDirPermissions(r.beadsDir); err != nil {
return fmt.Errorf("fs: CreateBeadsDir: fix perms %s: %w", r.beadsDir, err)
}
return nil
}
func (r *beadsDirFSRepositoryImpl) BeadsDirExists(ctx context.Context) (bool, error) {
info, err := os.Stat(r.beadsDir)
if errors.Is(err, os.ErrNotExist) {
return false, nil
}
if err != nil {
return false, fmt.Errorf("fs: BeadsDirExists: stat %s: %w", r.beadsDir, err)
}
return info.IsDir(), nil
}
View on GitHub (pinned to 71377f2769)
Solutions
- Check the wrapped %w cause in the error message (e.g. 'permission denied', 'not a directory') and fix the filesystem condition directly
- Verify the parent path of beadsDir exists and is writable: ls -ld $(dirname <beadsDir>) and mkdir -p it manually if needed
- If a regular file exists at beadsDir, remove or rename it so the directory can be created
- Ensure the process user has write permission on the target location, or run from a writable working directory
Example fix
// before
repo := fsrepo.New(fsrepo.WithBeadsDir("/proc/self/beads"))
repo.CreateBeadsDir(ctx) // mkdir /proc/self/beads: permission denied
// after
beadsDir := filepath.Join(os.Getenv("HOME"), "project", ".beads")
os.MkdirAll(filepath.Dir(beadsDir), 0o755) // ensure writable parent
repo.CreateBeadsDir(ctx) Defensive patterns
Strategy: validation
Validate before calling
func canCreateDir(path string) error {
fi, err := os.Stat(path)
if err == nil && !fi.IsDir() {
return fmt.Errorf("%s is a file, not a directory", path)
}
for dir := filepath.Dir(path); ; dir = filepath.Dir(dir) {
if err := unix.Access(dir, unix.W_OK|unix.X_OK); err != nil {
return fmt.Errorf("%s not writable: %v", dir, err)
}
if dir == filepath.Dir(dir) { return nil }
}
}
if err := canCreateDir(beadsDir); err != nil { return err }
repo.CreateBeadsDir(ctx) Type guard
func isMkdirErr(err error) bool {
var pe *fs.PathError
return errors.As(err, &pe) && pe.Op == "mkdir"
} Try / catch
if err := repo.CreateBeadsDir(ctx); err != nil {
var pe *fs.PathError
if errors.As(err, &pe) && errors.Is(pe.Err, syscall.EACCES) {
return fmt.Errorf("cannot create %s: check ownership/permissions of parent dirs", pe.Path)
}
return err
} Prevention
- Run bd from a directory writable by the current user, not system or root-owned paths
- Never pre-create .beads as root or with sudo in shared environments
- Check for stray files named .beads before initializing
- In containers, mount the workspace volume read-write
When it happens
Trigger: Calling CreateBeadsDir (e.g. via bd init) when os.MkdirAll(r.beadsDir, config.BeadsDirPerm) fails: parent directory does not exist and cannot be created, permission denied, path component is a regular file, disk full, or read-only filesystem.
Common situations: Running bd inside a read-only mount or container filesystem; beadsDir points under a path owned by another user; a stale file named .beads exists where the directory should be; umask/capability restrictions in CI sandboxes.
Related errors
- failed to create planning repo: %w
- ensureProxiedServerConfig: mkdir %s: %w
- cannot create shared server directory %s: %w
- cannot create shared dolt directory %s: %w
- create beads dir: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/50000310658043ea.
Report an issue: GitHub.