Skip to content

fix(sqlmesh): resolve DuckDB connection-config conflict blocking state init#32

Merged
Doctacon merged 3 commits into
mainfrom
fix/sqlmesh-state-conn-conflict
Apr 23, 2026
Merged

fix(sqlmesh): resolve DuckDB connection-config conflict blocking state init#32
Doctacon merged 3 commits into
mainfrom
fix/sqlmesh-state-conn-conflict

Conversation

@Doctacon
Copy link
Copy Markdown
Owner

Summary

Fixes ticket:sqlmesh-state-conn-conflict. The sqlmesh_project asset was crashing on first run with "Can't open a connection to same database file with a different configuration than existing connections" before any model materialized. Two-part fix in packages/databox/:

  1. config/settings.py::sqlmesh_config() — register only the gateway matching settings.backend. SQLMesh's Context.engine_adapters eagerly builds an EngineAdapter for every gateway in Config.gateways, so registering both made DATABOX_BACKEND=local still open a MotherDuck connection at snapshot-evaluation time. Dedicated state_connection at data/sqlmesh_state.duckdb is retained on both paths.
  2. orchestration/_factories.py::ensure_motherduck_databases() — open duckdb.connect(database=..., config={"custom_user_agent": f"SQLMesh/{__version__}"}) so the md: URL config matches SQLMesh's later open. DuckDB caches a process-global handle per md:?motherduck_token=... URL and rejects subsequent opens with mismatched config dicts.

Also sweeps in two pre-existing local-main commits: fix(orchestration): restore Dagster loading + switch to -m entry points (surfaced this bug) and chore: remove examples/ top-level dir.

Test plan

  • task verify (smoke) ends with RUN_SUCCESS under DATABOX_BACKEND=local on a clean data/ dir
  • task verify (smoke) ends with RUN_SUCCESS under DATABOX_BACKEND=motherduck on a clean data/ dir
  • uv run ruff check packages/ transforms/ clean
  • uv run mypy packages/ — 50 source files, no issues
  • tests/test_motherduck_autocreate.py updated for new kwargs-based duckdb.connect call signature

Evidence: .loom/evidence/20260423-sqlmesh-state-conn-conflict-fix.md.

🤖 Generated with Claude Code

Doctacon and others added 3 commits April 22, 2026 18:58
Two changes that landed together because they were found together:

1. analytics.py: drop `from __future__ import annotations` and import
   `AssetExecutionContext` directly instead of via `dg.AssetExecutionContext`.
   Dagster's op-definition validator does an identity check against the
   imported class; PEP 563 turns annotations into strings and the `dg.X`
   attribute form doesn't compare equal. Result: `defs` wouldn't load at
   all since the prior strict-mypy commit introduced the typed `context`
   parameter.

2. Taskfile.yaml: `dagster asset materialize -f <path>` → `-m databox.orchestration.definitions`.
   `dagster dev` drops `-f` entirely — it auto-discovers workspace.yaml
   at the repo root. workspace.yaml itself switches from `python_file`
   to `python_module` so both entry points target the same import path.

Validated with `dagster definitions validate` against both `-m` and
`-w workspace.yaml`.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
37 lines of 1Password source code do not justify a top-level directory.
Inlined into docs/secrets.md alongside the existing wiring example — same
"copy-adapt" intent, fewer directories. CLAUDE.md reference dropped.

Reconciled closed loom ticket secrets-pluggable with a follow-up note so
the graph stays truthful — the file was present at close time but has
since been removed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…e init

Two-part fix for the md: URL connection-config conflict that was crashing
`sqlmesh_project` on first run under both backends:

1. `config/settings.py::sqlmesh_config()` now registers only the gateway
   matching `settings.backend`. SQLMesh's `Context.engine_adapters` eagerly
   builds an EngineAdapter for every gateway in `Config.gateways`, so
   registering both made `DATABOX_BACKEND=local` still open a MotherDuck
   connection. A dedicated `state_connection` at `data/sqlmesh_state.duckdb`
   is retained on both paths.

2. `orchestration/_factories.py::ensure_motherduck_databases()` now opens
   `duckdb.connect(database=..., config={"custom_user_agent": f"SQLMesh/{__version__}"})`
   so the md: URL config matches SQLMesh's later open. DuckDB caches a
   process-global handle per `md:?motherduck_token=...` URL and rejects
   subsequent opens with mismatched config dicts.

Verified on a clean `data/` dir: `task verify` ends with RUN_SUCCESS under
both `DATABOX_BACKEND=local` and `DATABOX_BACKEND=motherduck`. Ruff + mypy
clean. See `.loom/evidence/20260423-sqlmesh-state-conn-conflict-fix.md`.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@Doctacon Doctacon merged commit 3b328c2 into main Apr 23, 2026
15 checks passed
@Doctacon Doctacon deleted the fix/sqlmesh-state-conn-conflict branch April 23, 2026 02:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant