gastownhall/beads · error

legacy SQLite issue %s uses unsupported removed fields

Error message

legacy SQLite issue %s uses unsupported removed fields

What it means

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.

Source

Thrown at internal/migration/legacysqlite/reader.go:568

// present created_at/updated_at invariants every legacy issue must satisfy.
func checkRequiredScalars(issue *types.Issue) error {
	if issue.ID == "" {
		return fmt.Errorf("legacy SQLite issue has empty ID")
	}
	if issue.Status == "tombstone" {
		return fmt.Errorf("legacy SQLite issue %s is a tombstone", issue.ID)
	}
	if issue.CreatedAt.IsZero() || issue.UpdatedAt.IsZero() {
		return fmt.Errorf("legacy SQLite issue %s has invalid created_at or updated_at", issue.ID)
	}
	return nil
}

// checkRemovedFields rejects legacy rows that populate columns the current
// schema no longer supports, then validates the tri-state boolean columns.
func (x legacyExtras) checkRemovedFields(issue *types.Issue) error {
	if 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 != ".") {
		return fmt.Errorf("legacy SQLite issue %s uses unsupported removed fields", issue.ID)
	}
	for _, b := range []struct {
		name string
		v    sql.NullInt64
	}{{"ephemeral", x.ephemeral}, {"pinned", x.pinned}, {"is_template", x.template}} {
		if b.v.Valid && b.v.Int64 != 0 && b.v.Int64 != 1 {
			return fmt.Errorf("issue %s has invalid %s boolean", issue.ID, b.name)
		}
	}
	return nil
}

type currentVarchar struct {
	name, value string
	maxRunes    int
}

type currentString struct {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Identify which field is populated: sqlite3 legacy.db "SELECT * FROM issues WHERE id='<id>'" and compare against the removed-column list
  2. Clear/NULL the unsupported columns in the legacy DB before migrating
  3. 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
  4. Re-run the migration

Example fix

// before
UPDATE issues SET agent_state='running', source_repo='/path/to/repo' WHERE id='<id>';
// after
UPDATE issues SET agent_state=NULL, source_repo=NULL WHERE id='<id>';
-- preserve info in description instead:
UPDATE issues SET description = description || '\n(agent_state was: running)' WHERE id='<id>';
Defensive patterns

Strategy: validation

Validate before calling

-- run before migration against the removed-column list
SELECT id FROM issues
WHERE closed_by IS NOT NULL OR deleted_by IS NOT NULL
   OR delete_reason IS NOT NULL OR original_type IS NOT NULL
   OR hook_bead IS NOT NULL OR role_bead IS NOT NULL
   OR agent_state IS NOT NULL OR last_activity IS NOT NULL
   OR role_type IS NOT NULL OR rig IS NOT NULL
   OR deleted_at IS NOT NULL OR crystallizes != 0
   OR (source_repo IS NOT NULL AND source_repo != '' AND source_repo != '.');

Type guard

REMOVED_COLUMNS = ['closed_by','deleted_by','delete_reason','original_type','hook_bead','role_bead','agent_state','last_activity','role_type','rig']
def uses_removed_fields(row) -> bool:
    if any(row.get(c) for c in REMOVED_COLUMNS):
        return True
    sr = row.get('source_repo')
    return bool(sr) and sr != '.'

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/8e25cb324ed66fda. Report an issue: GitHub.