Troubleshooting
Common failures, checked against the current CLI. Paid linting is called out where it applies.
Can't connect
- Confirm the process can reach the database.
- Check
database.url/DBLIFT_DB_URL/--db-url. A strayDBLIFT_DB_URLbeats YAML. - Then:
dblift db validate-configdblift db diagnose-connectiondblift db check-connectiondblift db list-drivers
check-connection is the connection test. There is no db test-connection.
A role that connects but lacks a privilege is reported with the database's own message (PostgreSQL permission denied for schema …, for example), not as Connection failed: invalid credentials. An authentication failure still uses the credentials wording.
A missing extra shows up as an import error at connect time, not at pip install dblift. Install the extra that matches database.type — dblift[postgresql], dblift[mysql], dblift[mariadb], dblift[oracle], dblift[sqlserver], dblift[db2], dblift[duckdb], dblift[cosmosdb], dblift[mongodb], dblift[redshift], dblift[snowflake], or the matching PostgreSQL-family extra. See the capability matrix. There is no dblift[sqlite] extra; SQLite uses the stdlib.
The wrong environment ran
Environment name selection is --env (or the API keyword) → DBLIFT_ENV (or resolve.env_var) → resolve.branch_map matched against resolve.branch_var. An unknown name fails fast and lists configured names — including when no environments: section exists.
Value merge is CLI args → env vars → file → defaults. Named-environment YAML is merged into the file layer before that.
dblift info after a migrate I already ran
Re-running migrate does not error with "already applied". Pending scripts run; applied ones are skipped. Use dblift info to see state. Common display values: Success, Pending, Failed, Out of order, Undone. Others exist (Baseline, Missing, Outdated, Needs repair, …).
To change an applied version, add a new versioned file. Do not edit an applied script unless you intend a checksum mismatch.
Out of order
A versioned file whose version is lower than the highest applied version is still applied by default. migrate logs a warning and continues. dblift info then labels that row Out of order.
--strict / strict_mode: true refuses that on migrate and validate: pending versioned scripts must not sit below the highest applied version, and every successful applied row must still have a script on disk (baselines and undo rows excluded). migrate --strict raises StrictModeError and tells you to renumber or rerun without --strict.
After the fact, without strict mode: rename the file to a newer version, or skip execution with dblift migrate --mark-as-executed --versions 1.0.5 only when the change is already in the database.
Undo did nothing / refused
undo runs the paired U<version>__*.sql (or .py) newest-first. A versioned migration with no undo companion cannot be reversed. Preview with dblift undo --target-version 1.0.0 --dry-run --show-sql.
Special characters in SQL files
migrations:
script_encoding: "utf-8"
detect_encoding: true # only for mixed/unknown legacy filesDefault is strict script_encoding (utf-8). Decode failure stops the run; characters are not silently corrupted.
Failed migrate
dblift info— look at the failed row.- Read the command log. The result may set
failed_history_persisted. - If that flag is false, the history table may not contain the failure; use DB logs plus the DBLift log.
- On auto-commit engines (MySQL, MariaDB, Oracle, YugabyteDB, Snowflake) or document stores, inspect objects that already landed.
dblift repaironly after you decide whether the failed or missing row should be reconciled.
The in-process statement journal enriches command results during a run only. It is not written to disk. Durable evidence is the command log (text / json / html), dblift_schema_history, and database logs.
Lock held
Another migrate may still be running. Check the process list, then native locks (PostgreSQL advisory, SQL Server application, MySQL named, Oracle/DB2, Cosmos lock documents). Table fallback: dblift_migration_lock in the target schema — delete a row only when its owner is confirmed dead. Then dblift info before retrying migrate.
History out of sync
dblift validatedblift repair
repair rewrites history metadata (checksums, failed rows, missing/extra rows). It does not mutate schema objects.
If the schema-history table cannot be created — a reader role on an empty schema — validate errors with ConnectionError (Could not create the schema-history table: ...) instead of returning a validation result. --format json is {"success": false, "error": "ConnectionError: ..."}. error is null on a successful validate, not "". Missing applied files are reported only with --strict, and only when the history table already has applied rows.
Start over (dev only)
dblift clean --dry-rundblift clean --clean-enabled
clean is disabled unless --clean-enabled (or config) turns it on. It drops managed objects including the history table.
SQL failed to parse or run
- History / checksum / ordering:
dblift validate(needs the configured database). - Offline rule lint of
.sqlfiles:dblift validate-sql(Pro command; packs and profiles need Enterprise). - Test the statement in a client for the same dialect.
Python migrations are not linted by validate-sql. validate is not a SQL parser.
Document store: DBLIFT-NOSQL-001
A .sql file against Cosmos DB or MongoDB fails before execute:
DBLIFT-NOSQL-001: '<file>.sql' is a SQL migration, but the '<dialect>' dialectdoes not execute SQL migrations.
Rewrite as V1_0_0__….py and drive context.db / context.raw_client. See Python migrations.
Already-applied .sql history rows stay valid if you leave the file in place. Cosmos pseudo-SQL (DROP CONTAINER, SET THROUGHPUT, …) is not translated.
On Cosmos DB, NoSqlWriteNotSupportedError means a Python migration passed a write to context.execute(); only native SELECT runs there. An AttributeError on context.database or context.client means the script predates the rename to context.db / context.raw_client.
MongoDB: DBLIFT-NOSQL-002
context.execute(...) always fails on MongoDB (no string query language). Use context.db["users"].find(...) or collection write methods.
Cosmos / Mongo connection
Cosmos: endpoint + key or managed identity; local emulator is typically port 8081.
MongoDB: url (mongodb:// / mongodb+srv://) or host/port; database is required even when url is set. Atlas often needs authSource=admin in the URI. Local default port is 27017.
SQLite path
Use an absolute path or a path relative to the working directory. The directory must exist. Three slashes is relative (sqlite:///./app.db); four slashes is absolute (sqlite:////abs/path/app.db).
Multiple directories / tags
migrations:
directories:
- ./migrations/core
- ./migrations/featuresPaths are relative to the config file. dblift info lists what was discovered.
Tags live in the filename: V1_0_0__migration[tag1,tag2].sql. Matching is case-sensitive. Filter with --tags tag1,tag2.
SQL Server notes
Full-text CREATE FULLTEXT CATALOG / CREATE FULLTEXT INDEX cannot share a transaction with ordinary DDL — put them in their own versioned file. Mixing them fails with:
Error: Migration V1__create_schema.sql mixes transactional and autocommit-on SQL
Unqualified DDL follows the login DEFAULT_SCHEMA, which is catalog state shared across connections. DBLift sets it with ALTER USER ... WITH DEFAULT_SCHEMA and warns if another session changed it. Use one login per --db-schema.