pola-rs/polars · error · TypeError

`path` argument has invalid type {qualified_type_name(path)!

Error message

`path` argument has invalid type {qualified_type_name(path)!r}, and cannot be turned into a sink target

What it means

The private helper `_to_sink_target` (py-polars/src/polars/lazyframe/engine.py:64) normalizes the `path` argument of every local sink operation (`sink_parquet`, `sink_ipc`, `sink_csv`, `sink_ndjson`). It only accepts `str`, `pathlib.Path`, an `io.IOBase` file object, a `PartitionBy` target, or any object with a callable `.write` attribute (custom writer). Any other type is rejected up front with this TypeError so the query never starts.

Source

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


def _to_sink_target(
    path: str | Path | IO[bytes] | IO[str] | PartitionBy,
) -> str | Path | IO[bytes] | IO[str] | PartitionBy:
    from polars.io.partition import PartitionBy

    if isinstance(path, (str, Path)):
        return normalize_filepath(path)
    elif isinstance(path, io.IOBase):
        return path
    elif isinstance(path, PartitionBy):
        return path
    elif callable(getattr(path, "write", None)):
        # This allows for custom writers
        return path
    else:
        msg = f"`path` argument has invalid type {qualified_type_name(path)!r}, and cannot be turned into a sink target"
        raise TypeError(msg)


def _with_monitoring(optimizations: QueryOptFlags) -> QueryOptFlags:
    """Register the query observer, and flag `optimizations` accordingly."""
    monitor = os.environ.get("POLARS_QUERY_MONITORING") == "1"
    if monitor:
        import polars._plr as plr

        plr.set_query_monitoring(True)

    optimizations = optimizations.__copy__()
    optimizations._pyoptflags.query_monitoring = monitor
    return optimizations


def _apply_retries_deprecation(
    retries: int | None, storage_options: StorageOptionsDict | None
) -> StorageOptionsDict | None:

View on GitHub (pinned to df599052da)

Solutions

  1. Pass a `str` or `pathlib.Path` file path: `lf.sink_parquet('out.parquet')`
  2. Pass a real opened binary file object, e.g. `open('out.parquet','wb')` or `io.BytesIO()`
  3. For partitioned multi-file output pass `pl.PartitionBy(...)` as the target
  4. For a custom destination, pass an object implementing a callable `.write` method, or use `lf.sink_batches(fn)` for per-batch callbacks

Example fix

# before
lf.sink_parquet(b'not-a-path')

# after
lf.sink_parquet('out.parquet')  # str/Path, open('out.parquet','wb'), or pl.PartitionBy(...)
Defensive patterns

Strategy: type-guard

Validate before calling

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

def is_sink_target(path: object) -> bool:
    return (
        isinstance(path, (str, Path, io.IOBase, PartitionBy))
        or callable(getattr(path, 'write', None))
    )

# before sinking:
assert is_sink_target(path), f'bad sink target: {type(path).__name__}'

Type guard

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

def is_sink_target(path: object) -> TypeGuard[str | Path | io.IOBase | PartitionBy]:
    return (
        isinstance(path, (str, Path, io.IOBase, PartitionBy))
        or callable(getattr(path, 'write', None))
    )

Try / catch

try:
    lf.sink_parquet(path)
except TypeError as e:
    if 'cannot be turned into a sink target' in str(e):
        raise ValueError(f'unsupported sink path {path!r}') from e
    raise

Prevention

When it happens

Trigger: Calling `lf.sink_parquet(path)` / `lf.sink_ipc(path)` / `lf.sink_csv(path)` / `lf.sink_ndjson(path)` (or the same on any local engine: in-memory, streaming, gpu, auto) with e.g. an int, `bytes`, a `list` of paths, `None`, `os.DirEntry`, or a test mock that has no `.write` method.

Common situations: Passing file content (`bytes`) instead of a file path; passing a list of paths expecting multi-file output (use `pl.PartitionBy` instead); passing a Path-like object from a third-party VFS library that is neither `io.IOBase` nor exposes `.write`; stubbing sinks in tests with objects that lack a callable `write`.

Related errors


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