{"record":{"id":"480c204722e63190","repo":"pola-rs/polars","slug":"sink-parquet-is-not-supported-by-type-self-n","errorCode":null,"errorMessage":"`sink_parquet` is not supported by {type(self).__name__}","messagePattern":"`sink_parquet` is not supported by (.+?)","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/lazyframe/engine.py","lineNumber":248,"sourceCode":"        compression_level: int | None,\n        statistics: bool | str | dict[str, bool],\n        row_group_size: int | None,\n        data_page_size: int | None,\n        maintain_order: bool,\n        storage_options: StorageOptionsDict | None,\n        credential_provider: CredentialProviderFunction | Literal[\"auto\"] | None,\n        retries: int | None,\n        sync_on_close: SyncOnCloseMethod | None,\n        metadata: ParquetMetadata | None,\n        arrow_schema: ArrowSchemaExportable | None,\n        mkdir: bool,\n        lazy: bool,\n        optimizations: QueryOptFlags,\n        sinked_paths_callback: SinkedPathsCallback | None,\n    ) -> LazyFrame | None:\n        \"\"\"See :meth:`polars.LazyFrame.sink_parquet`.\"\"\"\n        msg = f\"`sink_parquet` is not supported by {type(self).__name__}\"\n        raise NotImplementedError(msg)\n\n    def sink_ipc(\n        self,\n        lf: LazyFrame,\n        path: str | Path | IO[bytes] | PartitionBy,\n        *,\n        compression: IpcCompression | None,\n        compat_level: CompatLevel | None,\n        record_batch_size: int | None,\n        maintain_order: bool,\n        storage_options: StorageOptionsDict | None,\n        credential_provider: CredentialProviderFunction | Literal[\"auto\"] | None,\n        retries: int | None,\n        sync_on_close: SyncOnCloseMethod | None,\n        mkdir: bool,\n        lazy: bool,\n        optimizations: QueryOptFlags,\n        _record_batch_statistics: bool,","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/lazyframe/engine.py#L230-L266","documentation":"`Engine.sink_parquet` (engine.py:248) is the optional hook behind `LazyFrame.sink_parquet` for writing a query result to Parquet without materializing it in memory. Its default `Engine` stub raises `NotImplementedError` naming the engine. All built-in engines implement it — `_LocalEngine` subclasses directly and `RemoteEngine` via Polars Cloud — so in practice this error comes from custom `Engine` subclasses that only implement the abstract `collect`/`execute`.","triggerScenarios":"`lf.sink_parquet(path, engine=my_engine)` where `my_engine` is a user-defined `pl.Engine` subclass without a `sink_parquet` override. Commonly a stub/test engine or an in-progress alternative backend.","commonSituations":"Writing a custom execution backend (e.g. pushing the plan to another query engine) and testing the full `LazyFrame` API surface; injecting a recording engine in tests that only implements collect; copying a minimal engine example from the docs and expecting all sink methods to work.","solutions":["Use a built-in engine for sinks: `lf.sink_parquet(path, engine='streaming')` (default) or `engine=pl.RemoteEngine()` for cloud URIs","Implement `sink_parquet(self, lf, path, *, ...)` on your `Engine` subclass with the exact keyword signature shown in the stub","Collect then write eagerly as a stopgap: `lf.collect().write_parquet(path)`","Check the engine supports sinks before dispatch (see defense) when engines are pluggable at runtime"],"exampleFix":"# before\nclass MyEngine(pl.Engine):\n    @property\n    def name(self): return 'my'\n    def collect(self, lf, *, optimizations, background=False, post_opt_callback=None): ...\n    def execute(self, lf, *, optimizations): ...\nlf.sink_parquet('out.parquet', engine=MyEngine())  # NotImplementedError\n\n# after: add the override\nclass MyEngine(pl.Engine):\n    ...\n    def sink_parquet(self, lf, path, *, compression, compression_level, statistics,\n                     row_group_size, data_page_size, maintain_order, storage_options,\n                     credential_provider, retries, sync_on_close, metadata, arrow_schema,\n                     mkdir, lazy, optimizations, sinked_paths_callback):\n        ...  # write lf's result to path","handlingStrategy":"validation","validationCode":"from polars.lazyframe.engine import Engine\n\ndef engine_can_sink(engine: pl.Engine, fmt: str = 'sink_parquet') -> bool:\n    return getattr(type(engine), fmt) is not getattr(Engine, fmt)\n\nif not engine_can_sink(my_engine, 'sink_parquet'):\n    my_engine = pl.StreamingEngine()  # or collect+write_parquet fallback","typeGuard":null,"tryCatchPattern":"try:\n    lf.sink_parquet(path, engine=my_engine)\nexcept NotImplementedError as e:\n    if 'sink_parquet' in str(e):\n        lf.collect().write_parquet(path)  # eager fallback\n    else:\n        raise","preventionTips":["Give custom engines a capability matrix and test every sink against it","Default sinks to a built-in engine unless the custom one explicitly declares sink support","During backend development, implement all sink_* overloads together or gate them"],"tags":["polars","engine","sink","parquet","not-implemented","plugin"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}