{"record":{"id":"fd2c85c7657e095a","repo":"gastownhall/beads","slug":"failed-to-migrate-database-s-to-s-w","errorCode":null,"errorMessage":"failed to migrate database %s to %s: %w","messagePattern":"failed to migrate database (.+?) to (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/init.go","lineNumber":2408,"sourceCode":"\t\t// No old databases to migrate\n\t\treturn nil\n\t}\n\n\tif len(oldDBs) > 1 {\n\t\t// Multiple databases found - ambiguous, require manual intervention\n\t\treturn fmt.Errorf(\"multiple database files found in %s: %v\\nPlease manually rename the correct database to %s and remove others\",\n\t\t\ttargetDir, oldDBs, targetName)\n\t}\n\n\t// Migrate the single old database\n\toldDB := oldDBs[0]\n\tif !quiet {\n\t\tfmt.Fprintf(os.Stderr, \"→ Migrating database: %s → %s\\n\", filepath.Base(oldDB), targetName)\n\t}\n\n\t// Rename the old database to the new canonical name\n\tif err := os.Rename(oldDB, targetPath); err != nil {\n\t\treturn fmt.Errorf(\"failed to migrate database %s to %s: %w\", oldDB, targetPath, err)\n\t}\n\n\tif !quiet {\n\t\tfmt.Fprintf(os.Stderr, \"✓ Database migration complete\\n\\n\")\n\t}\n\n\treturn nil\n}\n\n// errWorkspaceAlreadyInitialized marks the benign \"this workspace already has a\n// database\" outcome from checkExistingBeadsData. --init-if-missing treats only\n// this case as an idempotent skip; any other error from the check is operational\n// (e.g. an unreadable .beads/embeddeddolt directory) and must still abort rather\n// than be silently masked as success.\nvar errWorkspaceAlreadyInitialized = errors.New(\"workspace already initialized\")\n\n// workspaceExistsError carries a user-facing \"already initialized\" message while\n// still matching errWorkspaceAlreadyInitialized via errors.Is, so callers can","sourceCodeStart":2390,"sourceCodeEnd":2426,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/init.go#L2390-L2426","documentation":"migrateOldDatabases renames the single discovered legacy database (os.Rename(oldDB, targetPath)) to the canonical beads.db name. This error wraps that rename failure, naming both the source and destination paths. bd throws it because the migration must be atomic: if the rename fails the old database stays put and init aborts rather than creating a fresh, empty database beside existing data.","triggerScenarios":"Running `bd init` when os.Rename(oldDB, targetPath) fails — most commonly the target path already exists (though the function stats it earlier, a race or symlink can cause EXDEV/EPERM/EEXIST), source and destination are on different filesystems (EXDEV), or the source file vanished or is not writable by the current user.","commonSituations":"Running on a filesystem that does not support atomic rename semantics (some network mounts return EXDEV or ENOSYS); another bd process or editor recreating beads.db concurrently; the legacy .db file sitting on a different volume than .beads (e.g. BEADS_DIR on a symlink into another mount); permission changes after the file was created by another user (e.g. root in a container).","solutions":["Check for and remove any partially created target file at the destination path, then re-run bd init.","If source and target are on different filesystems, move the file manually into .beads first (cp then rm) and re-run init.","Fix ownership/permissions on the old .db file and the .beads directory (e.g. sudo chown -R $USER .beads) if the process cannot rename it.","On network/overlay filesystems where rename fails, copy the database manually: mv <old>.db .beads/beads.db, then run bd init again."],"exampleFix":"// before\n$ bd init\n# failed to migrate database .beads/issues.db to .beads/beads.db: rename ... invalid cross-device link\n\n// after: move within the same filesystem\n$ mv -f .beads/issues.db .beads/beads.db\n$ bd init  # target exists, migration skipped","handlingStrategy":"retry","validationCode":"// Preflight: ensure rename is possible on the same filesystem\nif fi, err := os.Stat(targetPath); err == nil {\n    return fmt.Errorf(\"target %s already exists (size %d); remove it or skip migration\", targetPath, fi.Size())\n}\nif sameDevice, _ := onSameFilesystem(oldDB, targetPath); !sameDevice {\n    return fmt.Errorf(\"%s and %s are on different filesystems; copy manually\", oldDB, targetPath)\n}","typeGuard":null,"tryCatchPattern":"if err := migrateOldDatabases(targetPath, quiet); err != nil {\n    var pe *fs.PathError\n    if errors.As(err, &pe) && errors.Is(pe.Err, syscall.EXDEV) {\n        // fall back to copy+delete across filesystems, then re-run init\n    }\n    return err\n}","preventionTips":["Keep .beads and any legacy DB files on the same filesystem/volume (watch for BEADS_DIR symlinks crossing mounts).","Ensure no other bd process or editor holds or recreates beads.db during init.","Normalize file ownership after running bd as root in containers (chown -R $USER .beads).","Prefer local filesystems over network mounts for .beads to get atomic rename semantics."],"tags":["filesystem","migration","rename","init"],"backgroundTag":"rename-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}