gastownhall/beads · error
create beads directory: %w
Error message
create beads directory: %w
What it means
`bd bootstrap`'s sync action ensures the `.beads` directory exists before cloning from the remote, because in the fresh-clone path remote data may be detected before `.beads` is created (GH#2792). If `os.MkdirAll` on the configured beads directory fails (permissions, read-only filesystem, path is a file), the error is wrapped as `create beads directory: ...`.
Source
Thrown at cmd/bd/bootstrap.go:722
count, err := importFromLocalJSONL(ctx, s, plan.JSONLFile)
if err != nil {
return fmt.Errorf("import from JSONL: %w", err)
}
if err := s.Commit(ctx, "bd bootstrap: import from issues.jsonl"); err != nil {
return fmt.Errorf("commit import: %w", err)
}
fmt.Fprintf(os.Stderr, "Imported %d issues from %s\n", count, plan.JSONLFile)
return nil
}
func executeSyncAction(ctx context.Context, plan BootstrapPlan, cfg *configfile.Config) error {
// Ensure .beads directory exists — it may not in the "fresh clone"
// bootstrap path where we detected remote data before .beads was
// created. Deferred here to preserve --dry-run semantics. (GH#2792)
if err := os.MkdirAll(plan.BeadsDir, 0o750); err != nil {
return fmt.Errorf("create beads directory: %w", err)
}
dbName := cfg.GetDoltDatabase()
if err := cloneFromRemote(ctx, plan.BeadsDir, plan.SyncRemote, dbName, cfg); err != nil {
return err
}
// Finalize the bootstrapped workspace so subsequent bd commands can open
// the cloned database. Without metadata.json and config.yaml,
// configfile.Load() returns nil, callers fall back to the default
// dolt_database name, and bd loses track of the cloned database —
// producing "no beads configuration found" and "Error 1105: no database
// selected" on bd status / bd dolt push in fresh clones. Every other
// bootstrap action (init, restore, jsonl-import) writes these files via
// newDoltStore + createConfigYaml; the sync path historically did not.
// (GH#3201)
if err := finalizeSyncedBootstrap(plan.BeadsDir, plan.SyncRemote, cfg, dbName); err != nil {
return errView on GitHub (pinned to 71377f2769)
Solutions
- Check that the repo root is writable: `ls -la .beads` — remove the blocking file if `.beads` exists as a regular file.
- Fix ownership/permissions: `chown`/`chmod` the repo directory or run in a writable location.
- If on a read-only mount (CI artifact checkout), copy the repo to a writable path first.
- Verify you are running `bd bootstrap` at the repository root where `.beads` belongs.
Example fix
// before (shell) $ touch .beads # accidentally created a file $ bd bootstrap // create beads directory: mkdir .beads: not a directory // after $ rm -f .beads $ bd bootstrap # succeeds
Defensive patterns
Strategy: validation
Validate before calling
# Pre-flight before bd bootstrap:
BEADS_DIR=.beads
if [ -e "$BEADS_DIR" ] && [ ! -d "$BEADS_DIR" ]; then echo "$BEADS_DIR exists and is not a directory"; exit 1; fi
[ -w . ] || { echo "repo root not writable"; exit 1; }
mount | grep -q ' ro,' && echo "filesystem mounted read-only" Try / catch
if err := executeSyncAction(ctx, plan, cfg); err != nil {
if strings.Contains(err.Error(), "create beads directory:") {
return fmt.Errorf("fix .beads path/permissions and re-run bootstrap: %w", err)
}
return err
} Prevention
- Never create a file named `.beads`; it shadows the directory.
- Run bootstrap in a writable checkout, not a read-only CI mount.
- Verify user ownership of the repo before bootstrap (avoid sudo-created dirs).
- Check the wrapped mkdir error for EACCES vs ENOTDIR vs ENOSPC.
When it happens
Trigger: Running `bd bootstrap` where `plan.BeadsDir` (typically `.beads`) cannot be created: parent directory not writable, a regular file named `.beads` exists, read-only mount, or restrictive umask/ownership.
Common situations: Bootstrapping inside a read-only CI checkout; `.beads` path colliding with a file; running in a container as a non-root user without volume write permissions.
Related errors
- write metadata.json: %w
- create config.yaml: %w
- failed to create dolt directory: %w
- failed to create lock file: %w
- dolt path is not executable
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/6e7e0896f6165ae3.
Report an issue: GitHub.