{"record":{"id":"81567f4bcea7f450","repo":"agalwood/Motrix","slug":"transfer-tables-missing","errorCode":"transfer_tables_missing","errorMessage":"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.\n\nAction: delete the database file and restart the app to recreate it on the current v1 schema.\n  rm '${dbPath}'","messagePattern":"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\\.\n\nAction: delete the database file and restart the app to recreate it on the current v1 schema\\.\n  rm '(.+?)'","errorType":"exception","errorClass":"StaleSchemaError","httpStatus":null,"severity":"critical","filePath":"src/core/session/migrations/index.ts","lineNumber":365,"sourceCode":"    }\n    const taskColumns = new Set(\n      (\n        db.prepare('PRAGMA table_info(tasks)').all() as Array<{ name: string }>\n      ).map((column) => column.name)\n    )\n    if (\n      !taskColumns.has('task_type') ||\n      !taskColumns.has('finished_at') ||\n      !taskColumns.has('error_message') ||\n      !taskColumns.has('error_code') ||\n      !taskColumns.has('error_detail_key') ||\n      !taskColumns.has('error_detail_params') ||\n      !taskColumns.has('diagnosis_revision')\n    ) {\n      throw new StaleSchemaError('canonical_task_columns_missing', dbPath)\n    }\n    if (!hasTransferSchema) {\n      throw new StaleSchemaError('transfer_tables_missing', dbPath)\n    }\n    if (!hasTaskFiles) {\n      throw new StaleSchemaError('new_tables_missing', dbPath)\n    }\n    if (current >= 2) {\n      const statusSchemas = db\n        .prepare(\n          `SELECT name, sql FROM sqlite_master\n           WHERE type = 'table' AND name IN ('tasks', 'task_instances')`\n        )\n        .all() as Array<{ name: string; sql: string }>\n      if (\n        statusSchemas.length !== 2 ||\n        statusSchemas.some((table) => !table.sql.includes(\"'metadata_ready'\"))\n      ) {\n        throw new StaleSchemaError('canonical_task_columns_missing', dbPath)\n      }\n    }","sourceCodeStart":347,"sourceCodeEnd":383,"githubUrl":"https://github.com/agalwood/Motrix/blob/1a708ee57746c434e2c67a44bbf0906a976afea4/src/core/session/migrations/index.ts#L347-L383","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before: transfer_totals or transfer_buckets missing\n# after\n  rm '${dbPath}'\n# restart; v1 creates both transfer tables","handlingStrategy":"try-catch","validationCode":"function hasTransferTables(db: import('better-sqlite3').Database): boolean {\n  const present = (name: string) => db.prepare(\"SELECT 1 FROM sqlite_master WHERE type='table' AND name=?\").get(name) !== undefined;\n  return present('transfer_totals') && present('transfer_buckets');\n}","typeGuard":"function isStaleSchemaError(e: unknown): e is StaleSchemaError { return e instanceof StaleSchemaError; }","tryCatchPattern":"try {\n  migrate(db);\n} catch (e) {\n  if (e instanceof StaleSchemaError && e.reason === 'transfer_tables_missing') {\n    // reset DB; transfer tables will be created on v1\n  } else throw e;\n}","preventionTips":["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."],"tags":["database","sqlite","migration","transfer","stale-schema"],"backgroundTag":null,"analyzedSha":"1a708ee57746c434e2c67a44bbf0906a976afea4","analyzedAt":"2026-08-12T16:18:09.346Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}