@dataclass on MigrationError breaks drift error reporting (TypeError instead of MigrationDriftError) #245

Closed
opened 2026-07-22 17:46:12 +00:00 by Mark · 5 comments
Owner

Overview

MigrationDriftError.__init__ crashes with a TypeError because the parent class MigrationError is decorated with @dataclass (no fields) and its generated __init__ only accepts self. When MigrationDriftError.__init__ calls super().__init__(message_string), Python raises:

TypeError: MigrationError.__init__() takes 1 positional argument but 2 were given

This means that when the migration system detects drift (checksum mismatch), it crashes instead of reporting the error properly. Both the db_migrate.py CLI tool and MeshLedger.__init__ are affected.

Impact

  1. Drift detection is effectively broken — when checksum drift occurs, the system crashes with TypeError instead of raising MigrationDriftError
  2. db_migrate.py CLI crashes immediately on any database with applied migrations where drift is present
  3. MeshLedger.__init__ → upgrade() → _applied_versions() path crashes when checksum mismatch is found
  4. The verify() catch block at line 930–933 catches MigrationDriftError but the TypeError propagates uncaught

Expected Behavior

When checksum drift is detected, MigrationDriftError should be raised with a descriptive message explaining which migration has a checksum mismatch.

Actual Behavior

A TypeError: MigrationError.__init__() takes 1 positional argument but 2 were given is raised instead, because super().__init__(msg) fails on the @dataclass-decorated parent.

File & Line

  • substrate/ledger/migrations.py:136-143

Root Cause

@dataclass
class MigrationError(Exception):
    """Base for migration errors."""

class MigrationDriftError(MigrationError):
    def __init__(self, migration_name: str, stored: str, computed: str):
        msg = f"..."
        super().__init__(msg)  # ← TypeError! MigrationError is @dataclass with no fields

Fix Options

  1. Remove @dataclass from MigrationError and add a manual __init__ that accepts an optional message
  2. Add init=False to @dataclass on MigrationError
  3. Add a @dataclass field to MigrationError that can hold the message
  4. Override __str__ to handle the message attribute

Steps to Reproduce

  1. Have an existing substrate/ledger.db with an applied migration whose stored checksum differs from the computed one (or run the migrations then manually alter migration SQL)
  2. Call scripts/db_migrate.py upgrade or start MeshLedger
  3. Observe TypeError: MigrationError.__init__() takes 1 positional argument but 2 were given instead of a MigrationDriftError

Detection

Found during post-deploy probe after fix commit 7c46ed3 (DATA-004).
See kanban card t_7ee26fdd for the full probe context.

## Overview `MigrationDriftError.__init__` crashes with a `TypeError` because the parent class `MigrationError` is decorated with `@dataclass` (no fields) and its generated `__init__` only accepts `self`. When `MigrationDriftError.__init__` calls `super().__init__(message_string)`, Python raises: ``` TypeError: MigrationError.__init__() takes 1 positional argument but 2 were given ``` This means that when the migration system detects drift (checksum mismatch), it crashes instead of reporting the error properly. Both the `db_migrate.py` CLI tool and `MeshLedger.__init__` are affected. ## Impact 1. Drift detection is effectively broken — when checksum drift occurs, the system crashes with TypeError instead of raising `MigrationDriftError` 2. `db_migrate.py` CLI crashes immediately on any database with applied migrations where drift is present 3. `MeshLedger.__init__` → `upgrade()` → `_applied_versions()` path crashes when checksum mismatch is found 4. The `verify()` catch block at line 930–933 catches `MigrationDriftError` but the TypeError propagates uncaught ## Expected Behavior When checksum drift is detected, `MigrationDriftError` should be raised with a descriptive message explaining which migration has a checksum mismatch. ## Actual Behavior A `TypeError: MigrationError.__init__() takes 1 positional argument but 2 were given` is raised instead, because `super().__init__(msg)` fails on the `@dataclass`-decorated parent. ## File & Line - `substrate/ledger/migrations.py:136-143` ## Root Cause ```python @dataclass class MigrationError(Exception): """Base for migration errors.""" class MigrationDriftError(MigrationError): def __init__(self, migration_name: str, stored: str, computed: str): msg = f"..." super().__init__(msg) # ← TypeError! MigrationError is @dataclass with no fields ``` ## Fix Options 1. Remove `@dataclass` from `MigrationError` and add a manual `__init__` that accepts an optional message 2. Add `init=False` to `@dataclass` on `MigrationError` 3. Add a `@dataclass` field to `MigrationError` that can hold the message 4. Override `__str__` to handle the message attribute ## Steps to Reproduce 1. Have an existing `substrate/ledger.db` with an applied migration whose stored checksum differs from the computed one (or run the migrations then manually alter migration SQL) 2. Call `scripts/db_migrate.py upgrade` or start `MeshLedger` 3. Observe `TypeError: MigrationError.__init__() takes 1 positional argument but 2 were given` instead of a `MigrationDriftError` ## Detection Found during post-deploy probe after fix commit `7c46ed3` (DATA-004). See kanban card t_7ee26fdd for the full probe context.
Author
Owner

QA FAILED — false-positive close (reopened 2026-08-04)

This issue was closed at 2026-08-04T04:34:57Z as part of the kanban reconciliation sweep, but no fix is on master. The bug is still live.

Independent verification on master HEAD 92521ce956

Bug reproduces live:

$ python -c "from substrate.ledger.migrations import MigrationDriftError; raise MigrationDriftError('001_init', 'aaa', 'bbb')"
BUG REPRODUCED on master: MigrationError.__init__() takes 1 positional argument but 2 were given

substrate/ledger/migrations.py line 118 still has @dataclass on MigrationError, exactly as the issue body reports.

Fix state

  • Branch fix/mesh-seed-244-dataclass-migrationerror (commit 07abae2): removes the @dataclass decorator — addresses the same root cause but titled under #244, not #245.
  • No PR opened for that branch.
  • No mesh-seed-245* branch exists.
  • Master HEAD does not include 07abae2.

What needs to happen

  1. Open a PR from fix/mesh-seed-244-dataclass-migrationerror into master (or rebase/cherry-pick to a properly-titled #245 branch).
  2. Wait for kilo-gsd preflight (ruff) + the Verify gate to pass.
  3. Merge to master.
  4. Then — and only then — close this issue.

Why the previous close was wrong

The kanban reconciliation sweep on 2026-08-04 closed multiple Forgejo issues across repos without verifying the fix existed on master. This is one of them. The same pattern was confirmed today on mesh-seed #176, #231, #252, #253, #256, #257, plus nodedesk #38, easystitch #109, docker_backup #20, and org_mode #17 — all reopened with evidence.

Reopened by tasker-worker on kanban card t_100d8388.

## QA FAILED — false-positive close (reopened 2026-08-04) This issue was closed at 2026-08-04T04:34:57Z as part of the kanban reconciliation sweep, but **no fix is on master**. The bug is still live. ### Independent verification on master HEAD 92521ce956cf0fc9fb19c4dc9f286f3fe87f70c1 Bug reproduces live: ``` $ python -c "from substrate.ledger.migrations import MigrationDriftError; raise MigrationDriftError('001_init', 'aaa', 'bbb')" BUG REPRODUCED on master: MigrationError.__init__() takes 1 positional argument but 2 were given ``` `substrate/ledger/migrations.py` line 118 still has `@dataclass` on `MigrationError`, exactly as the issue body reports. ### Fix state - Branch `fix/mesh-seed-244-dataclass-migrationerror` (commit `07abae2`): removes the `@dataclass` decorator — addresses the same root cause but titled under #244, not #245. - No PR opened for that branch. - No `mesh-seed-245*` branch exists. - Master HEAD does not include `07abae2`. ### What needs to happen 1. Open a PR from `fix/mesh-seed-244-dataclass-migrationerror` into master (or rebase/cherry-pick to a properly-titled #245 branch). 2. Wait for kilo-gsd preflight (ruff) + the Verify gate to pass. 3. Merge to master. 4. Then — and only then — close this issue. ### Why the previous close was wrong The kanban reconciliation sweep on 2026-08-04 closed multiple Forgejo issues across repos without verifying the fix existed on master. This is one of them. The same pattern was confirmed today on mesh-seed #176, #231, #252, #253, #256, #257, plus nodedesk #38, easystitch #109, docker_backup #20, and org_mode #17 — all reopened with evidence. Reopened by tasker-worker on kanban card t_100d8388.
Author
Owner

QA verification — 2026-08-04 (second-pass)

Re-verifying after the 12:05Z reopen to confirm state has not silently flipped.

Live state on master HEAD 92521ce9:

  • Issue: open (state=open, closed_at=null, labels=bug, blocked:preflight, triage-approved)
  • Master HEAD: 92521ce956
  • Fix branch fix/mesh-seed-244-dataclass-migrationerror: no longer exists on origin (only master, fix/mesh-seed-253-contract-id, mesh-seed-36-bone-compilation, slo-specs-150)
  • Open PRs: none
  • Most recent master commits (newest first): #250, #263 (lint), #36 (bone compilation), #150 (slo), #174 (mutation testing), #175 (SDKs), #57, #137, #148 — no #245 entry

Bug still reproduces on master:

$ python -c "from substrate.ledger.migrations import MigrationDriftError; raise MigrationDriftError('001_init', 'aaa', 'bbb')"
BUG REPRODUCED on master: TypeError: MigrationError.__init__() takes 1 positional argument but 2 were given

substrate/ledger/migrations.py:118 still has @dataclass on MigrationError. Exactly as the original issue body describes.

The previously-identified fix commit 07abae2 does resolve the bug — verified by checking out fix/mesh-seed-244-dataclass-migrationerror (still recoverable in local reflog): removing the @dataclass decorator on line 118 produces the correct MigrationDriftError with the descriptive drift message. The fix is 1 line, surgical, and correct.

QA verdict: FAIL — issue correctly remains open. No fix on master. The earlier reopen stands.

Re-verified by tasker-worker on kanban card t_bdc269f8.

## QA verification — 2026-08-04 (second-pass) Re-verifying after the 12:05Z reopen to confirm state has not silently flipped. **Live state on master HEAD `92521ce9`:** - Issue: open (state=open, closed_at=null, labels=bug, blocked:preflight, triage-approved) - Master HEAD: 92521ce956cf0fc9fb19c4dc9f286f3fe87f70c1 - Fix branch `fix/mesh-seed-244-dataclass-migrationerror`: no longer exists on origin (only `master`, `fix/mesh-seed-253-contract-id`, `mesh-seed-36-bone-compilation`, `slo-specs-150`) - Open PRs: none - Most recent master commits (newest first): #250, #263 (lint), #36 (bone compilation), #150 (slo), #174 (mutation testing), #175 (SDKs), #57, #137, #148 — no #245 entry **Bug still reproduces on master:** ``` $ python -c "from substrate.ledger.migrations import MigrationDriftError; raise MigrationDriftError('001_init', 'aaa', 'bbb')" BUG REPRODUCED on master: TypeError: MigrationError.__init__() takes 1 positional argument but 2 were given ``` `substrate/ledger/migrations.py:118` still has `@dataclass` on `MigrationError`. Exactly as the original issue body describes. **The previously-identified fix commit `07abae2` does resolve the bug** — verified by checking out `fix/mesh-seed-244-dataclass-migrationerror` (still recoverable in local reflog): removing the `@dataclass` decorator on line 118 produces the correct `MigrationDriftError` with the descriptive drift message. The fix is 1 line, surgical, and correct. **QA verdict: FAIL — issue correctly remains open.** No fix on master. The earlier reopen stands. Re-verified by tasker-worker on kanban card t_bdc269f8.
Author
Owner

QA verification — 2026-08-04 (third-pass)

Issue was false-positive closed at 2026-08-04T14:30:23Z — reopened.

Live state on master HEAD 92521ce956cf:

  • substrate/ledger/migrations.py:118 still has @dataclass on MigrationError
  • Bug reproduces identically:
TypeError: MigrationError.__init__() takes 1 positional argument but 2 were given
  • No fix branch exists on origin (fix/mesh-seed-244-dataclass-migrationerror was deleted)
  • No PR for #245 exists
  • No commit referencing #245 on master

Root cause: MigrationError is decorated with @dataclass (no fields), so its generated __init__ only accepts self. When MigrationDriftError.__init__ calls super().__init__(message_string), Python raises TypeError.

Fix: Remove @dataclass decorator from MigrationError (line 118). 1-line surgical fix, verified in reflog on the deleted branch.

QA verdict: FAIL — bug still live on master. Issue correctly remains open.

## QA verification — 2026-08-04 (third-pass) **Issue was false-positive closed at 2026-08-04T14:30:23Z** — reopened. **Live state on master HEAD `92521ce956cf`:** - `substrate/ledger/migrations.py:118` still has `@dataclass` on `MigrationError` - Bug reproduces identically: ``` TypeError: MigrationError.__init__() takes 1 positional argument but 2 were given ``` - No fix branch exists on origin (`fix/mesh-seed-244-dataclass-migrationerror` was deleted) - No PR for #245 exists - No commit referencing #245 on master **Root cause:** `MigrationError` is decorated with `@dataclass` (no fields), so its generated `__init__` only accepts `self`. When `MigrationDriftError.__init__` calls `super().__init__(message_string)`, Python raises TypeError. **Fix:** Remove `@dataclass` decorator from `MigrationError` (line 118). 1-line surgical fix, verified in reflog on the deleted branch. **QA verdict: FAIL — bug still live on master. Issue correctly remains open.**
Mark closed this issue 2026-08-04 17:39:11 +00:00
Author
Owner

Re-opened: false-positive close confirmed. Issue was closed but no fix commit exists on master. Re-adding triage-approved to route back through the pipeline.

Re-opened: false-positive close confirmed. Issue was closed but no fix commit exists on master. Re-adding triage-approved to route back through the pipeline.
Author
Owner

QA verified 2026-08-08: fix is on master. PR #266 (merge 134c00c, commit 07abae2 'fix #244: remove @dataclass from MigrationError') landed 2026-08-04T17:06:34Z - same root cause/fix as this issue (duplicate of #244, which closed at merge time). Verified on origin/master 3dd9456: @dataclass removed from MigrationError (migrations.py:118); MigrationDriftError/UnknownMigrationError/ChecksumMismatchError raise correctly; drift scenario raises MigrationDriftError (not TypeError) in status() and MeshLedger.init; verify() returns False on drift; db_migrate verify exits 1 on drift, 0 clean; 63/63 ledger+gates unit tests pass. Closing as completed.

QA verified 2026-08-08: fix is on master. PR #266 (merge 134c00c, commit 07abae2 'fix #244: remove @dataclass from MigrationError') landed 2026-08-04T17:06:34Z - same root cause/fix as this issue (duplicate of #244, which closed at merge time). Verified on origin/master 3dd9456: @dataclass removed from MigrationError (migrations.py:118); MigrationDriftError/UnknownMigrationError/ChecksumMismatchError raise correctly; drift scenario raises MigrationDriftError (not TypeError) in status() and MeshLedger.__init__; verify() returns False on drift; db_migrate verify exits 1 on drift, 0 clean; 63/63 ledger+gates unit tests pass. Closing as completed.
Mark 2026-08-08 09:07:08 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Mark/mesh-seed#245
No description provided.