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
- Pass a bytes, io.BytesIO, or a real (open, binary-mode) file object implementing read()
- Ensure the object is still open when polars reads it (don't close before collect())
- Give custom sources a read(self, size=-1) method returning bytes
- 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
- Pass paths/URLs/BytesIO instead of custom objects
- Keep handles open until collect()
- Custom sources: implement read(size=-1) -> bytes and test it standalone
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.