MasterRecord

Troubleshooting

Common errors and how to fix them.

If something isn’t working, it’s probably one of these.

“Cannot read or find Context file’AppContext.js’”#

The migration CLI resolves a context by file name. Your context must live in a file matching the name you pass:

bash
# file must be named AppContext.js
masterrecord enable-migrations AppContext

“The ‘path’ argument must be of type string”#

You passed an inline config object to env() on a version older than 1.3.0. Upgrade, or use the environment-file form.

SQLite tries to create /db at the filesystem root#

Your connection starts with a leading slash. Use a relative path so it resolves under the project root:

json
{ "AppContext": { "type": "better-sqlite3", "connection": "db/" } }

“near ‘)’: syntax error” when migrating#

Your entity defined fields as constructor object-literals instead of builder methods, so no columns were registered. Define fields as methods:

javascript
id(db)   { db.integer().primary().auto(); }   // ✅
title(db){ db.string(); }                       // ✅

Configuration missing settings for context#

Your env JSON isn’t keyed by the context class name. Wrap settings under the context key:

json
{ "AppContext": { "type": "postgres", "host": "..." } }

“ERR_INVALID_MODULE_SPECIFIER” on Linux after migrating on Windows#

A migration snapshot generated on Windows before 1.3.1 stored its contextLocation with backslashes (e.g. "..\\..\\AppContext.js"), which Linux treats as literal filename characters — so the CLI failed before running any migration. Upgrade to masterrecord@1.3.1: the CLI now normalizes path separators when reading and writing snapshots, so already-committed snapshots work without regeneration.

“Bulk insert failed, falling back to individual inserts” in your logs#

On versions before 1.3.1, saving a batch where rows populated different column sets (some rows leave optional fields unset) produced a malformed multi-row INSERT on MySQL/Postgres and silently fell back to slow per-row inserts. Upgrade to masterrecord@1.3.1 — heterogeneous batches now emit one statement per column signature and stay on the fast path, and omitted columns keep their database DEFAULT.

“masterrecord: table ‘X’ does not exist”#

The entity is registered but its table was never created — MasterRecord detects the engine’s missing-table error (SQLite no such table, MySQL ER_NO_SUCH_TABLE, Postgres 42P01) and fails loudly instead of silently returning nothing. Generate and run a migration:

bash
masterrecord add-migration AddX AppContext && masterrecord update-database AppContext
# or, in a Master app
master db new AddX && master db migrate

“No environment specified. Set the ‘master’ or ‘NODE_ENV’ environment variable”#

The context picks config/environments/env.<env>.json from NODE_ENV (or master). Set it for the process or the CLI run — master db … --env production sets it for you, and the scaffolded server.js defaults it to development:

bash
NODE_ENV=development npx masterrecord update-database AppContext

“Cannot read or find Context snapshot ‘appcontext_contextSnapShot.json’”#

add-migration / update-database need the snapshot that enable-migrations creates (EF creates it implicitly). Run it once — master db does this automatically when no snapshot exists:

bash
masterrecord enable-migrations AppContext

Migrations work on my machine but fail on a fresh database#

The symptom is an ALTER TABLE or a foreign key against a table that no migration ever creates: everything applies against the database you developed on, and update-databaseon an empty one stops at “no such table”. The cause is almost always schema created outside migrations — a bootstrap script, a hand-run CREATE TABLE, a restored dump.

Before 1.30.0 the snapshot was rewritten when migrations were applied, so that outside schema was recorded as though a migration had created it, and the next add-migration generated a delta on top of tables no migration builds. From 1.30.0 the snapshot is written only when a migration is authored — as in EF Core, where migrations add regenerates ModelSnapshot and database update never touches it — so this can no longer happen silently.

To repair a project already in this state, bring the outside schema under migrations:

bash
# 1. author a migration that creates the missing tables
masterrecord add-migration CatchUpBaseTables AppContext

# 2. tell the databases that already HAVE that schema it is applied,
#    without running it (EF: 'migrations script --idempotent' + history insert)
masterrecord baseline AppContext --all

# 3. verify the real invariant: every migration replays onto nothing
masterrecord update-database AppContext   # against a throwaway empty database

Then delete the bootstrap script. The rule to hold onto: if a table is not created by a migration, no database can be rebuilt from scratch — so make the fresh-database replay part of CI.

Writes vanish intermittently (save resolves, row unchanged)#

Almost always a context shared across requests — a module-level export default new AppContext()imported by every handler. A context is a unit of work; concurrent requests on one instance mix change sets and, on versions before 1.5.12, could silently drop another request’s write. Upgrade, and scope the context per request: master.addScoped('db', AppContext)this.db, or master.useScope() / new AppContext() + close() outside requests. Also check that every saveChanges() / save() is awaited and that the query was not asNoTracking() (no-tracking entities are detached — their edits are never saved). See Change Tracking & Context Lifetime.

“ConcurrencyError … MR_CONCURRENCY_CONFLICT”#

Not a bug — an UPDATE/DELETE affected 0 rows because the row was modified (token mismatch) or deleted by someone else since you loaded it. reload() the entities in err.entries, re-apply your changes and save again. See Transactions & Concurrency.

“Query argument error … expected N value(s) for parameter placeholders”#

The number of $$ placeholders in the lambda must equal the number of extra arguments. A common cause is passing a direction to orderBy() — use orderByDescending((p) => p.created_at) instead of orderBy((p) => p.created_at, 'desc').

Booleans read back as 1 / 0#

On SQLite and MySQL, versions before 1.22.1 returned the stored integer. Upgrade — db.boolean() columns now materialize as true/false on every read path.

Still stuck?#

Tip
Set LOG_SQL=true to print the exact SQL MasterRecord runs — invaluable for diagnosing query and migration issues. Open an issue with that output on the MasterRecord repo.