{"record":{"id":"0be3eba2a8005a09","repo":"pola-rs/polars","slug":"the-remote-engine-can-only-sink-to-a-uri-or-a-par","errorCode":null,"errorMessage":"the remote engine can only sink to a URI or a `PartitionBy`, got {qualified_type_name(path)!r}","messagePattern":"the remote engine can only sink to a URI or a `PartitionBy`, got (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/lazyframe/engine_remote.py","lineNumber":221,"sourceCode":"            result.lazy(),\n            optimizations=optimizations,\n            background=background,\n            post_opt_callback=post_opt_callback,\n        )\n\n    # -- Sinks --------------------------------------------------------------------\n\n    @staticmethod\n    def _sink_uri(path: Any) -> str | PartitionBy:\n        \"\"\"Validate a Polars Cloud sink target.\"\"\"\n        from polars.io.partition import PartitionBy\n\n        if not isinstance(path, (str, PartitionBy)):\n            msg = (\n                \"the remote engine can only sink to a URI or a `PartitionBy`, got \"\n                f\"{qualified_type_name(path)!r}\"\n            )\n            raise TypeError(msg)\n        return path\n\n    @staticmethod\n    def _reject_if_set(**kwargs: Any) -> None:\n        \"\"\"Reject options unsupported by Polars Cloud.\"\"\"\n        for name, value in kwargs.items():\n            if value:\n                msg = f\"`{name}` is not supported by the remote engine\"\n                raise ValueError(msg)\n\n    def sink_parquet(\n        self,\n        lf: LazyFrame,\n        path: str | Path | IO[bytes] | PartitionBy,\n        *,\n        compression: ParquetCompression,\n        compression_level: int | None,\n        statistics: bool | str | dict[str, bool],","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/lazyframe/engine_remote.py#L203-L239","documentation":"`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.","triggerScenarios":"`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.","commonSituations":"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.","solutions":["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)","For partitioned cloud output pass a `pl.PartitionBy(...)` target","To keep output local, use a local engine (`engine='streaming'`) instead of RemoteEngine","To bring results to this machine, use `lf.collect(engine=remote)` (warns about transfer) rather than a file-object sink"],"exampleFix":"# before\nlf.sink_parquet(Path('out.parquet'), engine=remote)  # TypeError\n\n# after\nlf.sink_parquet('s3://bucket/out.parquet', engine=remote)\n# or keep it local:\nlf.sink_parquet(Path('out.parquet'), engine='streaming')","handlingStrategy":"type-guard","validationCode":"from pathlib import Path\nfrom polars.io.partition import PartitionBy\n\ndef is_remote_sink_target(path: object) -> bool:\n    return isinstance(path, str) or isinstance(path, PartitionBy)\n\ndef remote_target(path) -> str:\n    if isinstance(path, Path):\n        raise TypeError('convert local Path to a URI string or use a local engine')\n    if not is_remote_sink_target(path):\n        raise TypeError(f'remote sinks need a URI string, got {type(path).__name__}')\n    return path","typeGuard":"from typing import TypeGuard\nfrom polars.io.partition import PartitionBy\n\ndef is_remote_sink_target(path: object) -> TypeGuard[str | PartitionBy]:\n    return isinstance(path, (str, PartitionBy))","tryCatchPattern":"try:\n    lf.sink_parquet(target, engine=remote)\nexcept TypeError as e:\n    if 'can only sink to a URI' in str(e):\n        lf.sink_parquet(str(target), engine=remote)\n    else:\n        raise","preventionTips":["Keep remote sinks on URI strings ('s3://...', 'abfs://...', 'gs://...')","Convert Path objects to strings only for genuine URI schemes; local paths need a local engine","Never hand file handles or custom writers to RemoteEngine sinks"],"tags":["polars","remote","sink","path","typeerror"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}