{"record":{"id":"cca5163ebdf08596","repo":"gastownhall/beads","slug":"uow-database-q-has-no-project-identity-metadata","errorCode":null,"errorMessage":"uow: database %q has no project identity (metadata._project_id) — the schema is managed by beads-team-server; ask your operator to provision it with 'bts init' (or heal an older bts database with 'bts migrate')","messagePattern":"uow: database %q has no project identity \\(metadata\\._project_id\\) — the schema is managed by beads-team-server; ask your operator to provision it with 'bts init' \\(or heal an older bts database with 'bts migrate'\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/uow/team_server_schema.go","lineNumber":77,"sourceCode":"\tif expectedProjectID == \"\" {\n\t\treturn nil\n\t}\n\t// A read error is surfaced rather than skipped: checkTeamServerSchema has\n\t// already proven the beads schema is present at this binary's version, so\n\t// the metadata table exists and a failure here is a real fault, not the\n\t// legacy-database case verifyProjectIdentity tolerates.\n\tdbProjectID, err := issueops.GetMetadataInTx(ctx, conn, \"_project_id\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"uow: team-server identity check on database %q: %w\", database, err)\n\t}\n\t// Unlike verifyProjectIdentity, an absent stored identity is NOT tolerated\n\t// here. adoptTeamServerIdentity refuses to attach to a bts database that\n\t// has no metadata._project_id at all, so for a team-server database this\n\t// is an already-invalid state rather than a legacy one — and soft-skipping\n\t// it would mean deleting one row from the shared database silently\n\t// disables this guard for every client.\n\tif dbProjectID == \"\" {\n\t\treturn fmt.Errorf(\n\t\t\t\"uow: database %q has no project identity (metadata._project_id) — the schema is managed by beads-team-server; ask your operator to provision it with 'bts init' (or heal an older bts database with 'bts migrate')\",\n\t\t\tdatabase)\n\t}\n\tif dbProjectID != expectedProjectID {\n\t\treturn fmt.Errorf(\n\t\t\t\"PROJECT IDENTITY MISMATCH — refusing to connect\\n\\n\"+\n\t\t\t\t\"  Local project ID (metadata.json):  %s\\n\"+\n\t\t\t\t\"  Database %q project ID:            %s\\n\\n\"+\n\t\t\t\t\"The team server is serving a DIFFERENT project's database.\\n\"+\n\t\t\t\t\"This can happen when:\\n\"+\n\t\t\t\t\"  - --database (or a --db name override) points at another project\\n\"+\n\t\t\t\t\"  - the configured dolt_database was repointed after 'bd init'\\n\"+\n\t\t\t\t\"  - the operator re-provisioned this database for another project\\n\\n\"+\n\t\t\t\t\"Check dolt_database in .beads/metadata.json and any --database/--db\\n\"+\n\t\t\t\t\"override. 'bd init --team-server' re-adopts the provisioned identity\\n\"+\n\t\t\t\t\"and never writes to the shared database, so it is safe to re-run.\",\n\t\t\texpectedProjectID, database, dbProjectID)\n\t}","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/uow/team_server_schema.go#L59-L95","documentation":"checkTeamServerIdentity refuses to connect when the database has no stored project identity (metadata._project_id is absent or empty). Unlike the legacy path, an empty identity is treated as an invalid state for a team-server database: soft-skipping would silently disable the project-mismatch guard for every client sharing the database.","triggerScenarios":"verifyTeamServerSchema → checkTeamServerIdentity finds schema OK but GetMetadataInTx returns \"\" for _project_id — e.g. the database was provisioned by an older bts that never wrote identity, or the metadata row was deleted.","commonSituations":"Older bts database provisioned before identity stamping existed; someone manually deleted the _project_id row; database restored from a partial backup missing metadata; schema OK but 'bts init' was interrupted.","solutions":["Ask the operator to heal the database with 'bts migrate' (which writes the identity)","Re-provision cleanly with 'bts init' if appropriate","Never manually insert _project_id; let bts generate it","Verify the database was not restored from an incomplete backup"],"exampleFix":"// before\nbd sync  # database has no project identity\n// after\nbts migrate   # operator heals identity metadata\nbd sync","handlingStrategy":"validation","validationCode":"-- preflight: confirm identity row exists before connecting\nSELECT value FROM metadata WHERE `key` = '_project_id';  -- must return a non-empty row","typeGuard":"func isMissingIdentity(err error) bool {\n  return err != nil && strings.Contains(err.Error(), \"has no project identity\")\n}","tryCatchPattern":"err := bdSync(ctx)\nif isMissingIdentity(err) {\n  // operator must heal/provision; client retry will not help\n  return fmt.Errorf(\"ask operator to run 'bts migrate' or 'bts init': %w\", err)\n}","preventionTips":["Never delete metadata._project_id rows manually","Run 'bts migrate' to heal databases provisioned by older bts versions","Verify backups include the metadata table before restoring","Confirm 'bts init' completed successfully (exit 0) before admitting bd clients"],"tags":["database","identity","team-server","metadata"],"backgroundTag":"missing-project-identity","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}