{"record":{"id":"08275aa923b83d6d","repo":"gastownhall/beads","slug":"migrating-config-to-metadata-json-w","errorCode":null,"errorMessage":"migrating config to metadata.json: %w","messagePattern":"migrating config to metadata\\.json: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/configfile/configfile.go","lineNumber":105,"sourceCode":"\t\t// Try legacy config.json location (migration path)\n\t\tlegacyPath := filepath.Join(beadsDir, \"config.json\")\n\t\tdata, err = os.ReadFile(legacyPath) // #nosec G304 - controlled path from config\n\t\tif os.IsNotExist(err) {\n\t\t\treturn nil, nil\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"reading legacy config: %w\", err)\n\t\t}\n\n\t\t// Migrate: parse legacy config, save as metadata.json, remove old file\n\t\tvar cfg Config\n\t\tif err := json.Unmarshal(data, &cfg); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"parsing legacy config: %w\", err)\n\t\t}\n\n\t\t// Save to new location\n\t\tif err := cfg.Save(beadsDir); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"migrating config to metadata.json: %w\", err)\n\t\t}\n\n\t\t// Remove legacy file (best effort: migration already saved to new location)\n\t\t_ = os.Remove(legacyPath)\n\n\t\treturn &cfg, nil\n\t}\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"reading config: %w\", err)\n\t}\n\n\tvar cfg Config\n\tif err := json.Unmarshal(data, &cfg); err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing config: %w\", err)\n\t}\n\n\treturn &cfg, nil\n}","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/configfile/configfile.go#L87-L123","documentation":"During the legacy config.json -> metadata.json migration inside Load(), after successfully parsing the legacy file, bd writes the migrated config with Config.Save. This error wraps any failure of that save (temp-file creation, write, chmod, rename inside the beads directory). The migration aborts and the legacy file is left in place, so the next Load retries the migration.","triggerScenarios":"Calling configfile.Load(beadsDir) when metadata.json is missing, config.json parses fine, but Save fails because the beads dir is read-only, disk is full, permissions deny writing metadata.json, or .beads was deleted between read and save.","commonSituations":"Read-only checkouts or mounted volumes; .beads owned by another user; disk quota exceeded; a stale metadata.json.tmp-* left by a crashed process (harmless, but a full filesystem is not).","solutions":["Check write permissions on the .beads directory (ls -ld .beads) and fix with chown/chmod","Free disk space if the filesystem is full","Remove stale metadata.json.tmp-* files, then rerun bd","If the directory is intentionally read-only, migrate the config on a writable machine or run bd once with elevated access"],"exampleFix":"// before\n$ bd ready\nError: parsing... migrating config to metadata.json: permission denied\n// after\n$ chmod u+w .beads && bd ready","handlingStrategy":"try-catch","validationCode":"info, err := os.Stat(beadsDir)\nif err != nil || !info.IsDir() {\n\treturn fmt.Errorf(\"beads dir missing\")\n}\nif f, err := os.OpenFile(filepath.Join(beadsDir, \".write-probe\"), os.O_CREATE|os.O_WRONLY, 0o600); err != nil {\n\treturn fmt.Errorf(\"beads dir not writable: %w\", err)\n} else {\n\tf.Close(); os.Remove(filepath.Join(beadsDir, \".write-probe\"))\n}","typeGuard":null,"tryCatchPattern":"cfg, err := configfile.Load(beadsDir)\nif err != nil && strings.Contains(err.Error(), \"migrating config to metadata.json\") {\n\t// check disk space and .beads permissions, then retry Load\n\terr = retryLoad(beadsDir)\n}","preventionTips":["Keep .beads owned by the user running bd","Monitor disk space in CI runners","Avoid read-only mounts for workspaces that must migrate","Complete the migration once on a writable machine before distributing the workspace"],"tags":["filesystem","config","migration","permissions"],"backgroundTag":"config-write-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}