{"record":{"id":"011caa82afeac420","repo":"zylon-ai/private-gpt","slug":"cannot-resolve-sqlalchemy-engine-for-migration-sto","errorCode":null,"errorMessage":"Cannot resolve SQLAlchemy engine for migration store '{store}'","messagePattern":"Cannot resolve SQLAlchemy engine for migration store '(.+?)'","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"private_gpt/components/persistence/persistence_component.py","lineNumber":65,"sourceCode":"                client = LazySQLiteFactory.get_instance(self._settings)\n\n        self._clients[store] = client\n        return client\n\n    def _get_migration_backend(\n        self,\n        store: str,\n        client: Any,\n    ) -> MigrationBackend:\n        match store:\n            case \"postgres\" | \"sqlite\":\n                from private_gpt.components.migrations.backend.sqlalchemy_backend import (\n                    SQLAlchemyMigrationBackend,\n                )\n\n                engine = client.sync_session.kw.get(\"bind\")\n                if engine is None:\n                    raise ValueError(\n                        f\"Cannot resolve SQLAlchemy engine for migration store '{store}'\"\n                    )\n                return SQLAlchemyMigrationBackend(\n                    engine=engine,\n                    schema_name=self._settings.database.schema_name,\n                )\n            case _:\n                raise ValueError(f\"Unsupported store type: {store}\")\n\n    def apply_migrations(self) -> None:\n        with self._lock:\n            if self._migrations_applied:\n                logger.info(\"Migrations already applied in this process; skipping\")\n                return\n\n            store = self._settings.database.provider\n            schema = self._settings.database.schema_name\n            logger.info(","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/components/persistence/persistence_component.py#L47-L83","documentation":"When building the SQLAlchemy migration backend for 'postgres' or 'sqlite', the component extracts the engine via `client.sync_session.kw.get('bind')`. If the lazy client's sessionmaker was constructed without a bind engine (None), migrations cannot proceed and it raises `ValueError` naming the store. It indicates the persistence client was misconfigured at engine-creation time.","triggerScenarios":"Calling `apply_migrations()`/`revert_migrations()` when `LazyPostgresFactory`/`LazySQLiteFactory` produced a sessionmaker whose `bind` kwarg is None; custom client construction that defers or omits the engine; mocking the client in tests without a bound engine.","commonSituations":"Custom or partially-initialized database clients; test fakes replacing the persistence client; refactor of the factory changing how the engine is attached to the session.","solutions":["Verify the database client is created through the project's factory (`LazyPostgresFactory.get_instance` / `LazySQLiteFactory.get_instance`) so `sync_session.kw['bind']` is populated","Check database connection settings (URL/host/credentials) so engine creation succeeds instead of silently producing an unbound session","For tests, mock the client with `sync_session.kw = {'bind': create_engine(...)}`"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"client = persistence.get_client(settings.database.provider)\nengine = getattr(getattr(client, \"sync_session\", None), \"kw\", {}).get(\"bind\")\nif engine is None:\n    raise ValueError(\"persistence client session has no bound engine; check DB settings\")","typeGuard":"def client_has_bound_engine(client: Any) -> bool:\n    return getattr(getattr(client, \"sync_session\", None), \"kw\", {}).get(\"bind\") is not None","tryCatchPattern":"try:\n    persistence.apply_migrations()\nexcept ValueError as e:\n    if \"Cannot resolve SQLAlchemy engine\" in str(e):\n        raise SystemExit(\"database client misconfigured; check connection settings\") from e\n    raise","preventionTips":["Always construct DB clients via the project's Lazy factories so the engine is bound","Smoke-test apply_migrations in a staging env before deploying settings changes"],"tags":["persistence","migrations","sqlalchemy","misconfiguration"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}