gastownhall/beads · error
fs: CreateBeadsDir: beadsDir not resolved
Error message
fs: CreateBeadsDir: beadsDir not resolved
What it means
CreateBeadsDir creates the .beads directory (MkdirAll + permission fix), but the repository implementation guards that its beadsDir field was actually resolved during construction. This error is an internal invariant failure: a beadsDirFSRepositoryImpl was built without a resolved beads directory path, so creating it is unsafe.
Source
Thrown at internal/storage/domain/fs/beads.go:65
return domain.BeadsDirResolution{BeadsDir: r.beadsDir, HasExplicit: r.hasExplicit}
}
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)
}View on GitHub (pinned to 71377f2769)
Solutions
- Construct the repository via the normal factory/resolution path so beadsDir is set (or pass an explicit beads directory)
- Ensure bd is run inside a project root where .beads can be resolved, or pass the beads dir explicitly
- If you own the construction site, fail fast at construction when resolution returns an empty path instead of deferring to CreateBeadsDir
Example fix
// before
repo := &beadsDirFSRepositoryImpl{} // beadsDir unresolved
repo.CreateBeadsDir(ctx)
// after
repo := newBeadsDirFSRepository(resolvedBeadsDir) // factory resolves path
if resolvedBeadsDir == "" { return errors.New("beads dir could not be resolved") }
repo.CreateBeadsDir(ctx) Defensive patterns
Strategy: validation
Validate before calling
if beadsDir == "" {
return errors.New("beads dir not resolved; pass an explicit path or run inside a project root")
} Type guard
func beadsDirReady(r *fs.BeadsDirFSRepository, dir string) bool { return dir != "" } Try / catch
if err := repo.CreateBeadsDir(ctx); err != nil {
if strings.Contains(err.Error(), "beadsDir not resolved") {
// construction bug: rebuild via the factory with a resolved path
}
return err
} Prevention
- Always construct the FS repository through its factory so beadsDir is resolved
- Fail fast at construction when directory discovery returns an empty path
- Run inside a project root or pass the beads dir explicitly via flags/config
When it happens
Trigger: Calling CreateBeadsDir on a beadsDirFSRepositoryImpl constructed with an empty beadsDir — typically a construction/configuration bug where directory discovery (repo-root walk / explicit flag) failed silently or the constructor skipped resolution.
Common situations: Embedding beads as a library and instantiating the FS repository directly without running the directory-resolution step; running bd outside any git project root such that discovery yields nothing; misconfigured --path handling.
Related errors
- multiple .doltcfg directories detected
- no .beads directory found
- failed to inspect %s: %w
- resolving beads dir %s: %w
- resolving physical root %s: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/df04ff7bcc60e6f7.
Report an issue: GitHub.