agalwood/Motrix · critical · StaleSchemaError
transfer_tables_missing
transfer_tables_missing
Error message
The versioned database schema is incompatible with this build: expected tables `transfer_totals`/`transfer_buckets` are missing. 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 'transfer_tables_missing', thrown by Guard B at line 364 when either 'transfer_totals' or 'transfer_buckets' is absent. These are part of the inherited Plan A schema; their absence despite schema_version >= 1 indicates the DB is a partial/stale v1.
Source
Thrown at src/core/session/migrations/index.ts:365
}
const taskColumns = new Set(
(
db.prepare('PRAGMA table_info(tasks)').all() as Array<{ name: string }>
).map((column) => column.name)
)
if (
!taskColumns.has('task_type') ||
!taskColumns.has('finished_at') ||
!taskColumns.has('error_message') ||
!taskColumns.has('error_code') ||
!taskColumns.has('error_detail_key') ||
!taskColumns.has('error_detail_params') ||
!taskColumns.has('diagnosis_revision')
) {
throw new StaleSchemaError('canonical_task_columns_missing', dbPath)
}
if (!hasTransferSchema) {
throw new StaleSchemaError('transfer_tables_missing', dbPath)
}
if (!hasTaskFiles) {
throw new StaleSchemaError('new_tables_missing', dbPath)
}
if (current >= 2) {
const statusSchemas = db
.prepare(
`SELECT name, sql FROM sqlite_master
WHERE type = 'table' AND name IN ('tasks', 'task_instances')`
)
.all() as Array<{ name: string; sql: string }>
if (
statusSchemas.length !== 2 ||
statusSchemas.some((table) => !table.sql.includes("'metadata_ready'"))
) {
throw new StaleSchemaError('canonical_task_columns_missing', dbPath)
}
}View on GitHub (pinned to 1a708ee577)
Solutions
- Delete the DB and restart — migrate() creates both transfer tables on v1.
- If you intentionally disabled transfers in a fork, you must also relax this guard; otherwise reset.
- Confirm no schema-bootstrap step was skipped in your build.
Example fix
# before: transfer_totals or transfer_buckets missing
# after
rm '${dbPath}'
# restart; v1 creates both transfer tables Defensive patterns
Strategy: try-catch
Validate before calling
function hasTransferTables(db: import('better-sqlite3').Database): boolean {
const present = (name: string) => db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name=?").get(name) !== undefined;
return present('transfer_totals') && present('transfer_buckets');
} 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 === 'transfer_tables_missing') {
// reset DB; transfer tables will be created on v1
} else throw e;
} Prevention
- Do not fork the schema by removing transfer tables; if you do, also relax this guard deliberately.
- Reset dev DB when switching branches that touch the inherited schema.
- Confirm v1 migration source includes the transfer table DDL.
When it happens
Trigger: migrate() Guard B computes hasTransferSchema (transfer_totals AND transfer_buckets both present); if false, throws at line 365. Fires after the tasks-column check, before the task_files check.
Common situations: DB from a build that predated the transfer aggregation tables; an interrupted v1 migration; a custom build that disabled transfer tracking and never created the tables.
Related errors
- inherited_schema_missing
- canonical_task_columns_missing
- inspector_activity_schema_missing
- foreign_key_violation
- legacy_table_present
AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12).
Data as JSON: /api/errors/81567f4bcea7f450.
Report an issue: GitHub.