pola-rs/polars · error

no read method found

Error message

no read method found

What it means

PyFileLikeObject::to_buffer() slurps a Python file-like object by calling its read() method. call_method fails both when the attribute is missing and when calling it raises (closed file, network error), and this expect turns that into a panic reading 'no read method found'. It is reached from get_mmap_bytes_reader when a non-bytes, non-path object is passed to scan/read APIs that need the whole content in memory.

Source

Thrown at crates/polars-python/src/file.rs:75

/// Wraps a `PyObject`, and implements read, seek, and write for it.
impl PyFileLikeObject {
    /// Creates an instance of a `PyFileLikeObject` from a `PyObject`.
    /// To assert the object has the required methods,
    /// instantiate it with `PyFileLikeObject::require`
    pub(crate) fn new(object: Py<PyAny>, expects_str: bool, has_flush: bool) -> Self {
        PyFileLikeObject {
            inner: object,
            expects_str,
            has_flush,
        }
    }

    pub(crate) fn to_buffer(&self) -> Buffer<u8> {
        Python::attach(|py| {
            let bytes = self
                .inner
                .call_method(py, "read", (), None)
                .expect("no read method found");

            if let Ok(b) = bytes.cast_bound::<PyBytes>(py) {
                // SAFETY: we keep the underlying python object alive.
                let slice = b.as_bytes();
                let owner = bytes.clone_ref(py);
                let ss = unsafe { SharedStorage::from_slice_with_owner(slice, owner) };
                return Buffer::from_storage(ss);
            }

            if let Ok(b) = bytes.cast_bound::<PyString>(py) {
                return match b.to_cow().expect("PyString is not valid UTF-8") {
                    Cow::Borrowed(v) => {
                        // SAFETY: we keep the underlying python object alive.
                        let slice = v.as_bytes();
                        let owner = bytes.clone_ref(py);
                        let ss = unsafe { SharedStorage::from_slice_with_owner(slice, owner) };
                        return Buffer::from_storage(ss);
                    },

View on GitHub (pinned to df599052da)

Solutions

  1. Pass a bytes, io.BytesIO, or a real (open, binary-mode) file object implementing read()
  2. Ensure the object is still open when polars reads it (don't close before collect())
  3. Give custom sources a read(self, size=-1) method returning bytes
  4. Prefer passing a path/URL so polars controls the IO itself

Example fix

# before
class Src:  # no read() -> panic 'no read method found'
    pass
pl.read_csv(Src())

# after
from io import BytesIO
pl.read_csv(BytesIO(b"a,b\n1,2\n"))
# or
class Src:
    def read(self, size=-1): return b"a,b\n1,2\n"
pl.read_csv(Src())
Defensive patterns

Strategy: type-guard

Validate before calling

# Python: assert the protocol before passing to polars
def assert_readable(obj):
    assert callable(getattr(obj, "read", None)), "object must implement read() returning bytes"
    return obj

Type guard

from typing import Any

def is_binary_file_like(o: Any) -> bool:
    read = getattr(o, "read", None)
    return callable(read)

Try / catch

try:
    df = pl.read_csv(src)
except BaseException:  # PanicException from rust expect
    raise TypeError("source must be bytes, BytesIO, an open binary file, or a path") from None

Prevention

When it happens

Trigger: Passing an object without a read() method (a socket, a plain class, a path-like) where a file-like is expected, or passing a file-like whose read() raises — e.g. a closed file or a stream object whose read throws — to read_csv/read_ipc/read_parquet-style APIs.

Common situations: Passing a filename wrapped in an object, a text-mode wrapper that raises on binary read, an already-closed handle, or a mock without a proper read method; the up-front ensure_requirements() check exists but not all call paths run it before to_buffer().

Related errors


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