Skip to content

Records written before LMDB→RocksDB migration decode as plain objects — relationship getters, toJSON, and record methods unreachable #2012

Description

@Devin-Holland

Summary

On a database migrated LMDB→RocksDB via storage.migrateOnStart, records whose stored bytes predate the migration decode as plain Objects with no record prototype — so relationship accessors, toJSON, getUpdatedTime, etc. are unreachable on exactly those records. Records written after the migration decode as StoreRecordObject and behave normally. The failure is completely silent: reads return undefined, no errors logged.

This currently affects the dev central manager and is a blocker for migrating the prod CM, which has an even longer version history (this is being filed ahead of that attempt — prod cannot be broken this way).

Environment

  • Dev CM: harperfast/harper-pro:5.2.0-beta.3, RocksDB (migrated from LMDB via storage.migrateOnStart)
  • History (per Devin): started on an early 4.7 beta, moved through many 4.7.x releases over months → harper-pro 5.1.x (still LMDB — no Rocks migration at this step) → 5.2.0-beta.x, where storage.migrateOnStart performed the LMDB→RocksDB migration. The affected Organization record (2026-04-29) was written by an early-4.7-era build.
  • CM component: loadAsInstance = false resources, graphql schema with @relationships

Evidence (live inspector evals on the dev CM process)

The table is healthy — struct prototype has all relationship getters, resolvers installed:

{"protoNames":["constructor","allowRead","roles","clusters","settings"],
 "attrRels":[{"name":"roles","hasResolve":true},{"name":"clusters","hasResolve":true},{"name":"settings","hasResolve":true}]}

But per-record prototype linkage depends on when the record was last written:

record last written decodes as relationship getters
Cluster created post-migration 5.2/Rocks StoreRecordObject work
Cluster from 2026-07-09 (TERMINATED, untouched since) pre-migration plain Object 'clusters' in rec === false, reads undefined
Organization from 2026-04-29 pre-migration (4.7-era) plain Object unreachable
Host records (re-patched constantly by heartbeats) post-migration StoreRecordObject work

Downstream, this produced: GET /Organization/:id silently missing its clusters/settings relationship properties, and roleData.toJSON is not a function in permission checks (old hdb_role records lost toJSON the same way).

What does NOT reproduce it (important)

A clean-room reproduction of the same path does not show the bug: seed data on harperdb/harperdb:4.7.33 → boot harper-pro:5.2.0-beta.3 with storage.migrateOnStart=true → records on the migrated RocksDB store decode as StoreRecordObject and relationships resolve, including after restarts. So the trigger involves something in the real instance's history. Given the corrected history above, the leading candidate is records written by early 4.7 betas / older 4.7.x releases carrying older record-encoding metadata that the post-migration decoder doesn't link to the record prototype — my repro seeded with 4.7.33 (late 4.7), which likely already wrote the newer encoding. Other candidates: the migration ran under an earlier 5.2 beta than the currently-running one, or intermediate encoding states from the long 4.7.x upgrade chain.

Instance preserved for investigation

We are deliberately leaving the dev CM in the broken state (not running the rewrite workaround) so core can inspect affected records in situ — ping @Devin-Holland or devain for access/evals.

Observed workaround

Rewriting a record heals it (the constantly-patched Host records all decode correctly). A one-time no-op rewrite pass over pre-migration records would fix an affected instance — but the migration itself should either normalize record encoding or the decoder should attach the prototype for legacy-encoded records.

Asks

  1. Identify which per-record encoding state causes prototype-less decode after migration (dev CM is available for live inspection — happy to capture raw entry/encoder metadata for an affected vs healthy record pair on request).
  2. Make migrateOnStart re-encode (or the decoder tolerate) legacy records so long-history instances migrate safely.
  3. A verification query/operation we can run post-migration on prod to prove no records are in the broken state.

— filed by devain (Claude Fable 5) for @Devin-Holland; found while debugging the dev CM 5.2 upgrade (see central-manager#530 for the application-side fallout)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions