pola-rs/polars · error · NotImplementedError

`sink_ipc` is not supported by {type(self).__name__}

Error message

`sink_ipc` is not supported by {type(self).__name__}

What it means

`Engine.sink_ipc` (engine.py:271) is the optional `Engine` hook behind `LazyFrame.sink_ipc` (Arrow IPC/Feather output). Its default stub raises `NotImplementedError` naming the engine class. Every built-in engine supports it (`_LocalEngine` family natively, `RemoteEngine` through Polars Cloud), so the error signals a custom `Engine` subclass that did not override the method.

Source

Thrown at py-polars/src/polars/lazyframe/engine.py:271

        path: str | Path | IO[bytes] | PartitionBy,
        *,
        compression: IpcCompression | None,
        compat_level: CompatLevel | None,
        record_batch_size: int | None,
        maintain_order: bool,
        storage_options: StorageOptionsDict | None,
        credential_provider: CredentialProviderFunction | Literal["auto"] | None,
        retries: int | None,
        sync_on_close: SyncOnCloseMethod | None,
        mkdir: bool,
        lazy: bool,
        optimizations: QueryOptFlags,
        _record_batch_statistics: bool,
        sinked_paths_callback: SinkedPathsCallback | None,
    ) -> LazyFrame | None:
        """See :meth:`polars.LazyFrame.sink_ipc`."""
        msg = f"`sink_ipc` is not supported by {type(self).__name__}"
        raise NotImplementedError(msg)

    def sink_csv(
        self,
        lf: LazyFrame,
        path: str | Path | IO[bytes] | IO[str] | PartitionBy,
        *,
        include_bom: bool,
        compression: Literal["uncompressed", "gzip", "zstd"],
        compression_level: int | None,
        check_extension: bool,
        include_header: bool,
        separator: str,
        line_terminator: str,
        quote_char: str,
        batch_size: int,
        datetime_format: str | None,
        date_format: str | None,
        time_format: str | None,

View on GitHub (pinned to df599052da)

Solutions

  1. Use a built-in engine for the sink: `lf.sink_ipc(path, engine='streaming')` or `engine=pl.RemoteEngine()` for cloud targets
  2. Implement `sink_ipc` on your `Engine` subclass matching the stub's keyword signature (compression, compat_level, record_batch_size, maintain_order, storage_options, credential_provider, retries, sync_on_close, mkdir, lazy, optimizations, _record_batch_statistics, sinked_paths_callback)
  3. Stopgap: `lf.collect().write_ipc(path)`
  4. Gate sink calls on a capability check when the engine is selected at runtime

Example fix

# before
lf.sink_ipc('out.arrow', engine=my_custom_engine)  # NotImplementedError

# after
lf.sink_ipc('out.arrow', engine='streaming')
# or implement `sink_ipc` on MyEngine with the stub's signature
Defensive patterns

Strategy: validation

Validate before calling

from polars.lazyframe.engine import Engine

def engine_can_sink_ipc(engine: pl.Engine) -> bool:
    return type(engine).sink_ipc is not Engine.sink_ipc

engine = my_engine if engine_can_sink_ipc(my_engine) else pl.StreamingEngine()

Try / catch

try:
    lf.sink_ipc(path, engine=my_engine)
except NotImplementedError as e:
    if 'sink_ipc' in str(e):
        lf.collect().write_ipc(path)
    else:
        raise

Prevention

When it happens

Trigger: `lf.sink_ipc(path, engine=my_engine)` with a custom engine that only implements `collect`/`execute`. Typical with prototype backends or mock engines used in integration tests of sink pipelines.

Common situations: Teams extending Polars with an in-house backend (e.g. executing plans on a proprietary store) that covers collect but not sinks yet; test doubles that assert on plan construction but break when the fixture code calls a sink; tutorials on custom engines that predate the sink API.

Related errors


AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16). Data as JSON: /api/errors/5e63c3a3d7e8cefb. Report an issue: GitHub.