agalwood/Motrix · critical · StaleSchemaError

activity_schema_missing

activity_schema_missing

Error message

The versioned database schema is incompatible with this build: expected Dashboard activity tables, columns, singleton metadata, foreign-key/trigger policy, or the time-first activity index are invalid. This unpublished build updates the canonical v1 schema directly, so an existing local development database can have a valid version marker while its substantive tables are stale.

Action: delete the database file and restart the app to recreate it on the current v1 schema.
  rm '${dbPath}'

What it means

StaleSchemaError reason 'activity_schema_missing', thrown by Guard B at line 461 when the Dashboard activity schema is invalid on any of four axes: (1) hasExactSchemaObjects(ACTIVITY_SCHEMA_OBJECTS) false (DDL drift on task_activity_events/task_activity_meta), (2) activityTriggers.length !== 0 (any trigger on those tables), (3) an unexpected unique non-PK index exists on task_activity_events, or (4) the task_activity_meta singleton row is missing/malformed (id=1, non-empty generation, valid tracking_started_at, in-range revision, valid coverage_gap_at).

Source

Thrown at src/core/session/migrations/index.ts:462

      typeof activityMeta.generation === 'string' &&
      activityMeta.generation.length > 0 &&
      typeof activityMeta.tracking_started_at === 'bigint' &&
      activityMeta.tracking_started_at > 0n &&
      activityMeta.tracking_started_at <= BigInt(Number.MAX_SAFE_INTEGER) &&
      typeof activityMeta.revision === 'bigint' &&
      activityMeta.revision >= 0n &&
      activityMeta.revision <= BigInt(Number.MAX_SAFE_INTEGER - 2) &&
      (activityMeta.coverage_gap_at === null ||
        (typeof activityMeta.coverage_gap_at === 'bigint' &&
          activityMeta.coverage_gap_at > 0n &&
          activityMeta.coverage_gap_at <= BigInt(Number.MAX_SAFE_INTEGER)))
    if (
      !hasCanonicalActivityObjects ||
      activityTriggers.length !== 0 ||
      !hasNoUnexpectedUniqueActivityIndexes ||
      !hasActivityMeta
    ) {
      throw new StaleSchemaError('activity_schema_missing', dbPath)
    }
  }

  for (const m of MIGRATIONS) {
    if (m.version > current) {
      db.transaction(() => {
        m.up(db)
        db.prepare(
          'INSERT INTO schema_version (version, applied_at) VALUES (?, ?)'
        ).run(m.version, Date.now())
      })()
    }
  }

  validateCanonicalV3(db)
}

View on GitHub (pinned to 1a708ee577)

Solutions

  1. Delete the DB and restart — migrate() recreates the activity tables and seeds the singleton meta row.
  2. If preserving data, inspect task_activity_meta (should have exactly one row id=1 with valid fields) and DROP any non-PK unique indexes/triggers on task_activity_events.
  3. Confirm PRAGMA foreign_keys and safeIntegers handling are correct in your better-sqlite3 session — bigint range errors can corrupt the meta validation.

Example fix

# before: activity tables drifted / singleton meta missing / stray unique index
# after
  rm '${dbPath}'
# restart; migrate() builds activity tables and inserts the id=1 meta row
Defensive patterns

Strategy: try-catch

Validate before calling

function activitySchemaIsCanonical(db: import('better-sqlite3').Database): boolean {
  // mirror of migrate()'s check, simplified
  const triggers = db.prepare("SELECT 1 FROM sqlite_master WHERE type='trigger' AND tbl_name IN ('task_activity_events','task_activity_meta')").get();
  if (triggers) return false;
  const meta = db.prepare('SELECT id, generation, tracking_started_at, revision FROM task_activity_meta').get() as any;
  return !!meta && meta.id === 1 && typeof meta.generation === 'string' && meta.generation.length > 0;
}

Type guard

function isStaleSchemaError(e: unknown): e is StaleSchemaError { return e instanceof StaleSchemaError; }

Try / catch

try {
  migrate(db);
} catch (e) {
  if (e instanceof StaleSchemaError && e.reason === 'activity_schema_missing') {
    // reset DB; or DROP activity triggers/non-PK unique indexes and reseed task_activity_meta singleton
  } else throw e;
}

Prevention

When it happens

Trigger: migrate() Guard B (current > 0) performs the composite activity check at lines 395-460; if any of the four conditions fails, throws at line 462 with reason 'activity_schema_missing'.

Common situations: DB from a build predating the activity tables; an interrupted activity-schema bootstrap; a debug session that added a trigger or unique index on task_activity_events; corrupted/missing task_activity_meta singleton row from a failed INSERT; bigint range violation in revision/tracking_started_at from a clock-skew event.

Related errors


AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12). Data as JSON: /api/errors/c8b11151b5b9bea9. Report an issue: GitHub.