{"record":{"id":"f769e1c37cbdc062","repo":"gastownhall/beads","slug":"legacy-sqlite-issue-has-empty-id","errorCode":null,"errorMessage":"legacy SQLite issue has empty ID","messagePattern":"legacy SQLite issue has empty ID","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/migration/legacysqlite/reader.go","lineNumber":553,"sourceCode":"\n// applyCanonicalTimestamps normalizes the required created_at/updated_at values\n// to the canonical current-schema representation.\nfunc (x legacyExtras) applyCanonicalTimestamps(issue *types.Issue) error {\n\tvar err error\n\tif issue.CreatedAt, err = canonicalCurrentDatetime(issue.CreatedAt); err != nil {\n\t\treturn fmt.Errorf(\"legacy SQLite issue %s created_at: %w\", issue.ID, err)\n\t}\n\tif issue.UpdatedAt, err = canonicalCurrentDatetime(issue.UpdatedAt); err != nil {\n\t\treturn fmt.Errorf(\"legacy SQLite issue %s updated_at: %w\", issue.ID, err)\n\t}\n\treturn nil\n}\n\n// checkRequiredScalars enforces the non-empty ID, non-tombstone status, and\n// present created_at/updated_at invariants every legacy issue must satisfy.\nfunc checkRequiredScalars(issue *types.Issue) error {\n\tif issue.ID == \"\" {\n\t\treturn fmt.Errorf(\"legacy SQLite issue has empty ID\")\n\t}\n\tif issue.Status == \"tombstone\" {\n\t\treturn fmt.Errorf(\"legacy SQLite issue %s is a tombstone\", issue.ID)\n\t}\n\tif issue.CreatedAt.IsZero() || issue.UpdatedAt.IsZero() {\n\t\treturn fmt.Errorf(\"legacy SQLite issue %s has invalid created_at or updated_at\", issue.ID)\n\t}\n\treturn nil\n}\n\n// checkRemovedFields rejects legacy rows that populate columns the current\n// schema no longer supports, then validates the tri-state boolean columns.\nfunc (x legacyExtras) checkRemovedFields(issue *types.Issue) error {\n\tif nonempty(x.closedBy, x.deletedBy, x.deleteReason, x.originalType, x.hookBead, x.roleBead, x.agentState, x.lastActivity, x.roleType, x.rig) || x.deletedAt.Valid || x.crystallizes.Int64 != 0 || x.quality.Valid || (issue.SourceRepo != \"\" && issue.SourceRepo != \".\") {\n\t\treturn fmt.Errorf(\"legacy SQLite issue %s uses unsupported removed fields\", issue.ID)\n\t}\n\tfor _, b := range []struct {\n\t\tname string","sourceCodeStart":535,"sourceCodeEnd":571,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/migration/legacysqlite/reader.go#L535-L571","documentation":"checkRequiredScalars enforces that every legacy issue has a non-empty ID. This error means a row was read whose ID column is empty, which the current schema cannot represent — every issue requires a unique identifier. The migration aborts for that row.","triggerScenarios":"The legacy issues table contains a row with an empty (or whitespace) id value — typically a manually inserted row, a bulk import that left ids blank, or corruption from a failed write.","commonSituations":"Hand-rolled scripts or ETL jobs inserting issues without generating IDs; databases restored from partial backups.","solutions":["Find the bad row: sqlite3 legacy.db \"SELECT rowid FROM issues WHERE id = '' OR id IS NULL\"","Delete the row if it is junk, or assign it a proper unique ID in the legacy DB's ID format (e.g. 'bd-<n>' or the legacy prefix convention)","Check for other rows missing required fields in the same import batch","Re-run the migration"],"exampleFix":"// before\nUPDATE issues SET ... (row with empty id left in place)\n// after\nDELETE FROM issues WHERE id = '' OR id IS NULL;\n-- or\nUPDATE issues SET id = 'bd-1234' WHERE rowid = <rowid>;","handlingStrategy":"validation","validationCode":"-- run before migration\nSELECT rowid FROM issues WHERE id IS NULL OR trim(id) = '';","typeGuard":"def has_valid_id(row) -> bool:\n    return isinstance(row.get('id'), str) and row['id'].strip() != ''","tryCatchPattern":null,"preventionTips":["Enforce NOT NULL + non-empty id constraints in any custom writer","Never bulk-insert issues without generating IDs via the bd CLI","Check row counts against expectations before migrating"],"tags":["migration","sqlite","data-integrity"],"backgroundTag":"missing-required-field","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}