pola-rs/polars · error · TypeError

the remote engine can only sink to a URI or a `PartitionBy`,

Error message

the remote engine can only sink to a URI or a `PartitionBy`, got {qualified_type_name(path)!r}

What it means

`RemoteEngine._sink_uri` (engine_remote.py:216) validates every remote sink target and only accepts a URI `str` or a `PartitionBy` object; anything else raises TypeError with the qualified type name. This is stricter than local sinks (which accept `Path`, file handles, and custom writers) because Polars Cloud workers write directly to cloud/object storage identified by URI — a local file object would make no sense remotely.

Source

Thrown at py-polars/src/polars/lazyframe/engine_remote.py:221

            result.lazy(),
            optimizations=optimizations,
            background=background,
            post_opt_callback=post_opt_callback,
        )

    # -- Sinks --------------------------------------------------------------------

    @staticmethod
    def _sink_uri(path: Any) -> str | PartitionBy:
        """Validate a Polars Cloud sink target."""
        from polars.io.partition import PartitionBy

        if not isinstance(path, (str, PartitionBy)):
            msg = (
                "the remote engine can only sink to a URI or a `PartitionBy`, got "
                f"{qualified_type_name(path)!r}"
            )
            raise TypeError(msg)
        return path

    @staticmethod
    def _reject_if_set(**kwargs: Any) -> None:
        """Reject options unsupported by Polars Cloud."""
        for name, value in kwargs.items():
            if value:
                msg = f"`{name}` is not supported by the remote engine"
                raise ValueError(msg)

    def sink_parquet(
        self,
        lf: LazyFrame,
        path: str | Path | IO[bytes] | PartitionBy,
        *,
        compression: ParquetCompression,
        compression_level: int | None,
        statistics: bool | str | dict[str, bool],

View on GitHub (pinned to df599052da)

Solutions

  1. Pass the target as a URI string, e.g. `'s3://bucket/out.parquet'` (convert `Path` with `str(path)` only for local-URI sinks; cloud targets need a real scheme)
  2. For partitioned cloud output pass a `pl.PartitionBy(...)` target
  3. To keep output local, use a local engine (`engine='streaming'`) instead of RemoteEngine
  4. To bring results to this machine, use `lf.collect(engine=remote)` (warns about transfer) rather than a file-object sink

Example fix

# before
lf.sink_parquet(Path('out.parquet'), engine=remote)  # TypeError

# after
lf.sink_parquet('s3://bucket/out.parquet', engine=remote)
# or keep it local:
lf.sink_parquet(Path('out.parquet'), engine='streaming')
Defensive patterns

Strategy: type-guard

Validate before calling

from pathlib import Path
from polars.io.partition import PartitionBy

def is_remote_sink_target(path: object) -> bool:
    return isinstance(path, str) or isinstance(path, PartitionBy)

def remote_target(path) -> str:
    if isinstance(path, Path):
        raise TypeError('convert local Path to a URI string or use a local engine')
    if not is_remote_sink_target(path):
        raise TypeError(f'remote sinks need a URI string, got {type(path).__name__}')
    return path

Type guard

from typing import TypeGuard
from polars.io.partition import PartitionBy

def is_remote_sink_target(path: object) -> TypeGuard[str | PartitionBy]:
    return isinstance(path, (str, PartitionBy))

Try / catch

try:
    lf.sink_parquet(target, engine=remote)
except TypeError as e:
    if 'can only sink to a URI' in str(e):
        lf.sink_parquet(str(target), engine=remote)
    else:
        raise

Prevention

When it happens

Trigger: `lf.sink_parquet(Path('out.parquet'), engine=remote)`, passing an `io.BytesIO`/opened file, or a custom writer object to any `sink_*` call on a RemoteEngine. Note `pathlib.Path` — fine locally — is rejected here because it is not a URI string.

Common situations: Code written against local sinks reused with a remote engine without changing the path argument; passing `Path` objects built by application logic; attempting to 'capture' remote output into a buffer locally.

Related errors


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