{"record":{"id":"670b0789b6c6bb73","repo":"gastownhall/beads","slug":"checking-dolt-metadata-directory-s-w","errorCode":null,"errorMessage":"checking dolt metadata directory %s: %w","messagePattern":"checking dolt metadata directory (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/doltserver/doltserver.go","lineNumber":1910,"sourceCode":"// bdDoltMarker is written after a current bd process creates or acknowledges a\n// local Dolt repository. Its absence in an existing .dolt/ directory indicates\n// the database was created by a pre-0.56 bd version (which used embedded mode).\n// Those databases are incompatible with the current server-only architecture.\nconst bdDoltMarker = \".bd-dolt-ok\"\n\n// MarkDoltDirCompatible writes the canonical bd compatibility marker when\n// doltDir contains a local Dolt repository. It no-ops when there is no .dolt/\n// directory, which lets server and repair paths call it defensively.\nfunc MarkDoltDirCompatible(doltDir string) error {\n\tif doltDir == \"\" {\n\t\treturn errors.New(\"dolt directory is required\")\n\t}\n\tdotDolt := filepath.Join(doltDir, \".dolt\")\n\tif info, err := os.Stat(dotDolt); err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(\"checking dolt metadata directory %s: %w\", dotDolt, err)\n\t} else if !info.IsDir() {\n\t\treturn fmt.Errorf(\"dolt metadata path %s is not a directory\", dotDolt)\n\t}\n\tmarkerPath := filepath.Join(doltDir, bdDoltMarker)\n\tif _, err := os.Stat(markerPath); err == nil {\n\t\treturn nil\n\t} else if !os.IsNotExist(err) {\n\t\treturn fmt.Errorf(\"checking dolt compatibility marker %s: %w\", markerPath, err)\n\t}\n\tif err := os.WriteFile(markerPath, []byte(\"ok\\n\"), 0600); err != nil {\n\t\treturn fmt.Errorf(\"writing dolt compatibility marker %s: %w\", markerPath, err)\n\t}\n\treturn nil\n}\n\n// ensureDoltInit initializes a dolt database directory if .dolt/ doesn't exist.\n// If .dolt/ exists, seeds the .bd-dolt-ok marker for existing working databases.\n// See GH#2137 for background on pre-0.56 database compatibility.","sourceCodeStart":1892,"sourceCodeEnd":1928,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/doltserver/doltserver.go#L1892-L1928","documentation":"MarkDoltDirCompatible stats <doltDir>/.dolt to decide whether a local Dolt repository exists before writing the .bd-dolt-ok compatibility marker (internal/doltserver/doltserver.go:1910). A missing .dolt is a no-op success; this error is returned only when os.Stat fails for any other reason — permission denied, I/O error, too many symlinks, etc. The wrapped err is the raw *PathError, so the message includes the exact syscall failure.","triggerScenarios":"Calling MarkDoltDirCompatible (directly or via bd server/repair paths) where <doltDir>/.dolt exists but cannot be stat'ed: parent directory lacks execute/search permission, the path traverses an unavailable NFS/network mount, .dolt is a broken symlink chain, or the filesystem returns EIO.","commonSituations":"Repository on a disconnected network drive; directory permissions changed by a sync/backup tool; .dolt replaced by a dangling symlink; running bd under a different user than the one who owns ~/.beads or the repo's dolt dir.","solutions":["Read the wrapped os.PathError — the syscall (stat) and errno (e.g. permission denied) identify the cause.","Check permissions on the dolt dir and its parents: `ls -ld <doltDir> <doltDir>/.dolt` and each ancestor directory; fix with chmod/chown if bd runs as another user.","If the path is on a network/removable volume, remount it and retry.","If .dolt is a dangling symlink, remove it (`rm <doltDir>/.dolt`) so bd treats the dir as having no repo, then re-initialize.","Run `bd doctor` to diagnose the state of the local dolt directory."],"exampleFix":"// before: bd cannot stat .dolt because a backup tool replaced it with a dangling symlink\n$ ls -ld ~/.beads/dolt/.dolt\nlrwxr-xr-x 1 me me 20 ... .dolt -> /mnt/backup/.dolt (gone)\n// after\n$ rm ~/.beads/dolt/.dolt\n$ bd doctor   # re-init or repair as advised","handlingStrategy":"validation","validationCode":"// Validate the dolt dir is stat-able before invoking bd paths that call MarkDoltDirCompatible\nimport \"os\"\nfunc checkDoltDir(doltDir string) error {\n    info, err := os.Stat(doltDir)\n    if err != nil { return err }\n    if !info.IsDir() { return fmt.Errorf(\"%s is not a directory\", doltDir) }\n    if d := filepath.Join(doltDir, \".dolt\"); doltExists(d) {\n        if _, err := os.Stat(d); err != nil { return err } // surfaces permission/EIO early\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"// Go: distinguish permission problems from other failures and report the path\nif err := MarkDoltDirCompatible(dir); err != nil && strings.HasPrefix(err.Error(), \"checking dolt metadata directory\") {\n    var perr *os.PathError\n    if errors.As(err, &perr) && errors.Is(perr.Err, syscall.EACCES) {\n        return fmt.Errorf(\"fix permissions on %s (run as the owning user)\", dir)\n    }\n    return err\n}","preventionTips":["Run bd consistently as one user; avoid sudo invocations that change ownership of ~/.beads.","Keep Dolt data off network/synced mounts that can disappear or remount read-only.","Never symlink .dolt to external locations; keep repository metadata in place.","Run `bd doctor` periodically to catch permission/drive issues early."],"tags":["dolt","filesystem","permissions","stat"],"backgroundTag":"filesystem-permission-denied","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}