{"record":{"id":"8e25cb324ed66fda","repo":"gastownhall/beads","slug":"legacy-sqlite-issue-s-uses-unsupported-removed-fi","errorCode":null,"errorMessage":"legacy SQLite issue %s uses unsupported removed fields","messagePattern":"legacy SQLite issue (.+?) uses unsupported removed fields","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/migration/legacysqlite/reader.go","lineNumber":568,"sourceCode":"// 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\n\t\tv    sql.NullInt64\n\t}{{\"ephemeral\", x.ephemeral}, {\"pinned\", x.pinned}, {\"is_template\", x.template}} {\n\t\tif b.v.Valid && b.v.Int64 != 0 && b.v.Int64 != 1 {\n\t\t\treturn fmt.Errorf(\"issue %s has invalid %s boolean\", issue.ID, b.name)\n\t\t}\n\t}\n\treturn nil\n}\n\ntype currentVarchar struct {\n\tname, value string\n\tmaxRunes    int\n}\n\ntype currentString struct {","sourceCodeStart":550,"sourceCodeEnd":586,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/migration/legacysqlite/reader.go#L550-L586","documentation":"checkRemovedFields rejects legacy rows that populate columns the current schema no longer supports (closedBy, deletedBy, deleteReason, originalType, hookBead, roleBead, agentState, lastActivity, roleType, rig, deletedAt, crystallizes, quality), or whose SourceRepo is set to something other than empty/'.'. The migration cannot carry these fields forward, so the row fails validation.","triggerScenarios":"Migration reads a legacy issue row where any removed column is non-empty/non-default — e.g. agentState set by an orchestration layer, quality populated by a review tool, or source_repo pointing at a real repo path.","commonSituations":"Databases written by newer/experimental beads builds with features later removed; rows touched by external agents (GT/rig tooling) that populated role/rig columns; source_repo set by multi-repo setups.","solutions":["Identify which field is populated: sqlite3 legacy.db \"SELECT * FROM issues WHERE id='<id>'\" and compare against the removed-column list","Clear/NULL the unsupported columns in the legacy DB before migrating","Move needed information into supported fields (e.g. append deleteReason/agentState content into the issue description or notes) or a sidecar file, since the current schema stores such data as metadata, not columns","Re-run the migration"],"exampleFix":"// before\nUPDATE issues SET agent_state='running', source_repo='/path/to/repo' WHERE id='<id>';\n// after\nUPDATE issues SET agent_state=NULL, source_repo=NULL WHERE id='<id>';\n-- preserve info in description instead:\nUPDATE issues SET description = description || '\\n(agent_state was: running)' WHERE id='<id>';","handlingStrategy":"validation","validationCode":"-- run before migration against the removed-column list\nSELECT id FROM issues\nWHERE closed_by IS NOT NULL OR deleted_by IS NOT NULL\n   OR delete_reason IS NOT NULL OR original_type IS NOT NULL\n   OR hook_bead IS NOT NULL OR role_bead IS NOT NULL\n   OR agent_state IS NOT NULL OR last_activity IS NOT NULL\n   OR role_type IS NOT NULL OR rig IS NOT NULL\n   OR deleted_at IS NOT NULL OR crystallizes != 0\n   OR (source_repo IS NOT NULL AND source_repo != '' AND source_repo != '.');","typeGuard":"REMOVED_COLUMNS = ['closed_by','deleted_by','delete_reason','original_type','hook_bead','role_bead','agent_state','last_activity','role_type','rig']\ndef uses_removed_fields(row) -> bool:\n    if any(row.get(c) for c in REMOVED_COLUMNS):\n        return True\n    sr = row.get('source_repo')\n    return bool(sr) and sr != '.'","tryCatchPattern":null,"preventionTips":["Inventory legacy columns vs. the current schema before each migration","Relocate needed info into supported fields (description/metadata) ahead of time","Avoid experimental builds for production data","Keep source_repo empty/'.' unless the current schema supports it"],"tags":["migration","sqlite","schema","removed-columns"],"backgroundTag":"unsupported-legacy-columns","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}