{"record":{"id":"00be0cc60fc564d4","repo":"gastownhall/beads","slug":"persisting-sanitized-database-name-to-metadata-jso","errorCode":null,"errorMessage":"persisting sanitized database name to metadata.json: %w","messagePattern":"persisting sanitized database name to metadata\\.json: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/store_factory.go","lineNumber":220,"sourceCode":"\t\t_, newErr := os.Stat(newDir)\n\t\tswitch {\n\t\tcase newErr == nil:\n\t\t\treturn fmt.Errorf(\"cannot auto-migrate database: both %q and %q exist under %s; remove one manually and retry\",\n\t\t\t\toldName, newName, dataDir)\n\t\tcase !os.IsNotExist(newErr):\n\t\t\treturn fmt.Errorf(\"checking target directory %q: %w\", newDir, newErr)\n\t\tdefault:\n\t\t\tif err := os.Rename(oldDir, newDir); err != nil {\n\t\t\t\treturn fmt.Errorf(\"renaming database directory: %w\", err)\n\t\t\t}\n\t\t\tfmt.Fprintf(os.Stderr, \"bd: migrated database directory %q → %q (GH#3231)\\n\", oldName, newName)\n\t\t}\n\t}\n\n\tif cfg != nil && cfg.DoltDatabase != newName {\n\t\tcfg.DoltDatabase = newName\n\t\tif err := cfg.Save(beadsDir); err != nil {\n\t\t\treturn fmt.Errorf(\"persisting sanitized database name to metadata.json: %w\", err)\n\t\t}\n\t\tfmt.Fprintf(os.Stderr, \"bd: updated metadata.json dolt_database %q → %q (GH#3231)\\n\", oldName, newName)\n\t}\n\treturn nil\n}\n\n// newReadOnlyStoreFromConfig creates a read-only storage backend from the beads\n// directory's persisted metadata.json configuration.\n//\n// For embedded mode, invalid characters (hyphens, dots) are sanitized in-memory\n// only — no directory renames or metadata.json writes. This prevents cross-repo\n// hydration from mutating foreign projects (GH#3231).\nfunc newReadOnlyStoreFromConfig(ctx context.Context, beadsDir string) (storage.DoltStorage, error) {\n\treturn openNonMutatingStoreFromConfig(ctx, beadsDir, false)\n}\n\n// newPreviewStoreFromConfig is newReadOnlyStoreFromConfig for a preview\n// command (--dry-run, --inspect) reading a repository it was only pointed at:","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/store_factory.go#L202-L238","documentation":"migrateHyphenatedDB renames a hyphenated Dolt database directory and rewrites metadata.json (GH#3231). If cfg.Save(beadsDir) fails while persisting the sanitized dolt_database name, the error is wrapped so the migration failure is attributed to the metadata write, not the rename.","triggerScenarios":"During newDoltStoreFromConfig, when the configured DoltDatabase contains hyphens, the directory rename succeeds, but writing the updated metadata.json fails (read-only beads dir, permission denied, disk full, corrupt config file state).","commonSituations":"Read-only mount of the .beads directory; running bd under a user without write permission to metadata.json; disk quota exhaustion; concurrent processes holding conflicting writes.","solutions":["Check write permission on .beads/metadata.json and the beads dir for the running user.","Free disk space / check quota if Save failed on write.","Manually update dolt_database in metadata.json to the sanitized (underscore) name to match the renamed directory.","Retry the operation after fixing the environment; the rename is idempotent once metadata matches."],"exampleFix":"// after manual repair:\n# metadata.json\n\"dolt_database\": \"my_project_db\"   # was \"my-project-db\"; directory already renamed","handlingStrategy":"try-catch","validationCode":"mdPath := filepath.Join(beadsDir, \"metadata.json\")\nif info, err := os.Stat(mdPath); err != nil || info.Mode().Perm()&0200 == 0 {\n    // cannot persist sanitized name; fix permissions first\n}","typeGuard":null,"tryCatchPattern":"if err := migrateHyphenatedDB(beadsDir, oldName, newName, cfg); err != nil {\n    if strings.Contains(err.Error(), \"persisting sanitized database name\") {\n        // fix metadata.json writability, align dolt_database manually, retry\n    }\n    return err\n}","preventionTips":["Ensure .beads/metadata.json is writable by the bd process user.","Avoid hyphenated Dolt database names so migration never triggers.","Monitor disk space/quota on the workspace volume.","After any hyphenated migration, verify metadata.json dolt_database matches the renamed directory."],"tags":["migration","metadata","storage","filesystem"],"backgroundTag":"config-write-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}