{"record":{"id":"df04ff7bcc60e6f7","repo":"gastownhall/beads","slug":"fs-createbeadsdir-beadsdir-not-resolved","errorCode":null,"errorMessage":"fs: CreateBeadsDir: beadsDir not resolved","messagePattern":"fs: CreateBeadsDir: beadsDir not resolved","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/fs/beads.go","lineNumber":65,"sourceCode":"\treturn domain.BeadsDirResolution{BeadsDir: r.beadsDir, HasExplicit: r.hasExplicit}\n}\n\nfunc (r *beadsDirFSRepositoryImpl) BeadsDirIsLocal(ctx context.Context) bool {\n\tworkDir := filepath.Clean(utils.CanonicalizePath(r.workDir))\n\tbeadsDir := filepath.Clean(utils.CanonicalizePath(r.beadsDir))\n\tif beadsDir == workDir {\n\t\treturn true\n\t}\n\trel, err := filepath.Rel(workDir, beadsDir)\n\tif err != nil {\n\t\treturn false\n\t}\n\treturn rel != \"..\" && !strings.HasPrefix(rel, \"..\"+string(filepath.Separator))\n}\n\nfunc (r *beadsDirFSRepositoryImpl) CreateBeadsDir(ctx context.Context) error {\n\tif r.beadsDir == \"\" {\n\t\treturn fmt.Errorf(\"fs: CreateBeadsDir: beadsDir not resolved\")\n\t}\n\tif err := os.MkdirAll(r.beadsDir, config.BeadsDirPerm); err != nil {\n\t\treturn fmt.Errorf(\"fs: CreateBeadsDir: mkdir %s: %w\", r.beadsDir, err)\n\t}\n\tif _, err := config.FixBeadsDirPermissions(r.beadsDir); err != nil {\n\t\treturn fmt.Errorf(\"fs: CreateBeadsDir: fix perms %s: %w\", r.beadsDir, err)\n\t}\n\treturn nil\n}\n\nfunc (r *beadsDirFSRepositoryImpl) BeadsDirExists(ctx context.Context) (bool, error) {\n\tinfo, err := os.Stat(r.beadsDir)\n\tif errors.Is(err, os.ErrNotExist) {\n\t\treturn false, nil\n\t}\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"fs: BeadsDirExists: stat %s: %w\", r.beadsDir, err)\n\t}","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/fs/beads.go#L47-L83","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nrepo := &beadsDirFSRepositoryImpl{} // beadsDir unresolved\nrepo.CreateBeadsDir(ctx)\n// after\nrepo := newBeadsDirFSRepository(resolvedBeadsDir) // factory resolves path\nif resolvedBeadsDir == \"\" { return errors.New(\"beads dir could not be resolved\") }\nrepo.CreateBeadsDir(ctx)","handlingStrategy":"validation","validationCode":"if beadsDir == \"\" {\n    return errors.New(\"beads dir not resolved; pass an explicit path or run inside a project root\")\n}","typeGuard":"func beadsDirReady(r *fs.BeadsDirFSRepository, dir string) bool { return dir != \"\" }","tryCatchPattern":"if err := repo.CreateBeadsDir(ctx); err != nil {\n    if strings.Contains(err.Error(), \"beadsDir not resolved\") {\n        // construction bug: rebuild via the factory with a resolved path\n    }\n    return err\n}","preventionTips":["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"],"tags":["filesystem","configuration","beads-dir"],"backgroundTag":"unresolved-config-path","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}