{"record":{"id":"7e7f1a6f57c2481a","repo":"pola-rs/polars","slug":"no-read-method-found","errorCode":null,"errorMessage":"no read method found","messagePattern":"no read method found","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/polars-python/src/file.rs","lineNumber":75,"sourceCode":"/// Wraps a `PyObject`, and implements read, seek, and write for it.\nimpl PyFileLikeObject {\n    /// Creates an instance of a `PyFileLikeObject` from a `PyObject`.\n    /// To assert the object has the required methods,\n    /// instantiate it with `PyFileLikeObject::require`\n    pub(crate) fn new(object: Py<PyAny>, expects_str: bool, has_flush: bool) -> Self {\n        PyFileLikeObject {\n            inner: object,\n            expects_str,\n            has_flush,\n        }\n    }\n\n    pub(crate) fn to_buffer(&self) -> Buffer<u8> {\n        Python::attach(|py| {\n            let bytes = self\n                .inner\n                .call_method(py, \"read\", (), None)\n                .expect(\"no read method found\");\n\n            if let Ok(b) = bytes.cast_bound::<PyBytes>(py) {\n                // SAFETY: we keep the underlying python object alive.\n                let slice = b.as_bytes();\n                let owner = bytes.clone_ref(py);\n                let ss = unsafe { SharedStorage::from_slice_with_owner(slice, owner) };\n                return Buffer::from_storage(ss);\n            }\n\n            if let Ok(b) = bytes.cast_bound::<PyString>(py) {\n                return match b.to_cow().expect(\"PyString is not valid UTF-8\") {\n                    Cow::Borrowed(v) => {\n                        // SAFETY: we keep the underlying python object alive.\n                        let slice = v.as_bytes();\n                        let owner = bytes.clone_ref(py);\n                        let ss = unsafe { SharedStorage::from_slice_with_owner(slice, owner) };\n                        return Buffer::from_storage(ss);\n                    },","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/crates/polars-python/src/file.rs#L57-L93","documentation":"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.","triggerScenarios":"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.","commonSituations":"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().","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"],"exampleFix":"# before\nclass Src:  # no read() -> panic 'no read method found'\n    pass\npl.read_csv(Src())\n\n# after\nfrom io import BytesIO\npl.read_csv(BytesIO(b\"a,b\\n1,2\\n\"))\n# or\nclass Src:\n    def read(self, size=-1): return b\"a,b\\n1,2\\n\"\npl.read_csv(Src())","handlingStrategy":"type-guard","validationCode":"# Python: assert the protocol before passing to polars\ndef assert_readable(obj):\n    assert callable(getattr(obj, \"read\", None)), \"object must implement read() returning bytes\"\n    return obj","typeGuard":"from typing import Any\n\ndef is_binary_file_like(o: Any) -> bool:\n    read = getattr(o, \"read\", None)\n    return callable(read)","tryCatchPattern":"try:\n    df = pl.read_csv(src)\nexcept BaseException:  # PanicException from rust expect\n    raise TypeError(\"source must be bytes, BytesIO, an open binary file, or a path\") from None","preventionTips":["Pass paths/URLs/BytesIO instead of custom objects","Keep handles open until collect()","Custom sources: implement read(size=-1) -> bytes and test it standalone"],"tags":["python","file-like","io","api-misuse","panic","ffi"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}