BUG-HUNT: [consistency] ToolRunner.execute() uses allow_nan=True for host-routed tools but allow_nan=False for container-routed tools — NaN/Infinity silently passes through on host execution #6582

Open
opened 2026-04-09 21:46:58 +00:00 by HAL9000 · 0 comments
Owner

Bug Report: [consistency] — Inconsistent JSON NaN/Infinity handling between host and container execution paths

Severity Assessment

  • Impact: NaN or Infinity values in tool inputs pass the JSON serialization check on the host path (allow_nan=True) but would be rejected on the container path (allow_nan=False). These invalid JSON values are then forwarded to downstream consumers (LLM APIs, logging, storage) that parse strict RFC 7159 JSON, causing silent parse failures or data corruption.
  • Likelihood: Medium — occurs whenever a tool handler returns float NaN or Infinity, or an LLM injects one into tool arguments.
  • Priority: High

Location

  • File: src/cleveragents/tool/runner.py
  • Function: ToolRunner.execute
  • Lines: 459–470 (host path) vs. 412–419 (container path)

Description

ToolRunner.execute() has two JSON serialization validation gates — one for container-routed tools and one for host-routed tools. They use different allow_nan settings:

Container path (line 413):

# Validate input_schema and capabilities (T2) before
# delegating to the container executor so container-routed
# tools receive the same spec validation as host-routed ones.
try:
    json.dumps(inputs, allow_nan=False)   # <-- STRICT: rejects NaN/Inf
except (TypeError, ValueError) as exc:
    return ToolResult(...)

Host path (line 463):

# Validate that inputs are JSON-serialisable.  Host-routed tools
# use the default ``allow_nan=True`` for backward compatibility;
# only the container path enforces RFC 7159 (P1-1).
try:
    json.dumps(inputs)    # <-- LENIENT: allow_nan defaults to True, accepts NaN/Inf
except (TypeError, ValueError) as exc:
    return ToolResult(...)

The comment explicitly acknowledges this inconsistency ("backward compatibility") but this is the wrong place to be lenient — NaN and Infinity are not valid JSON per RFC 7159. When these values reach downstream consumers (LLM providers, databases, the audit log), they will fail to parse them, producing cryptic errors far removed from the source.

Similarly, the output validation at line 507–515 also uses allow_nan=True:

try:
    json.dumps(raw_output)   # allow_nan=True — NaN in output silently passes
except (TypeError, ValueError) as exc:
    ...

Expected Behavior

Both host and container paths should enforce RFC 7159-compliant JSON (allow_nan=False). If backward compatibility is required, a deprecation warning should be emitted rather than silently passing invalid values.

Actual Behavior

Tool inputs or outputs containing float('nan') or float('inf') are accepted by the host-path validation check, producing output like:

{"value": NaN}

which is not valid JSON and will cause json.loads() to raise JSONDecodeError in any RFC-compliant consumer.

Suggested Fix

Change both host-path json.dumps() calls to use allow_nan=False:

# Line 463 — input validation, host path
try:
    json.dumps(inputs, allow_nan=False)  # enforce RFC 7159 consistently
except (TypeError, ValueError) as exc:
    return ToolResult(
        success=False,
        output={},
        error=f"Inputs are not JSON-serialisable: {exc}",
        duration_ms=0.0,
    )

# Line 507 — output validation, host path
try:
    json.dumps(raw_output, allow_nan=False)  # enforce RFC 7159 consistently
except (TypeError, ValueError) as exc:
    ...

Category

consistency

TDD Note

After this bug issue is verified, a corresponding Type/Testing issue will be created for TDD. The test will use tags: @tdd_issue, @tdd_issue_<this-issue-number>, and @tdd_expected_fail to prove the bug exists before fixing it.


Automated by CleverAgents Bot
Supervisor: Bug Hunting | Agent: bug-hunter

## Bug Report: [consistency] — Inconsistent JSON NaN/Infinity handling between host and container execution paths ### Severity Assessment - **Impact**: NaN or Infinity values in tool inputs pass the JSON serialization check on the host path (`allow_nan=True`) but would be rejected on the container path (`allow_nan=False`). These invalid JSON values are then forwarded to downstream consumers (LLM APIs, logging, storage) that parse strict RFC 7159 JSON, causing silent parse failures or data corruption. - **Likelihood**: Medium — occurs whenever a tool handler returns float NaN or Infinity, or an LLM injects one into tool arguments. - **Priority**: High ### Location - **File**: `src/cleveragents/tool/runner.py` - **Function**: `ToolRunner.execute` - **Lines**: 459–470 (host path) vs. 412–419 (container path) ### Description `ToolRunner.execute()` has two JSON serialization validation gates — one for container-routed tools and one for host-routed tools. They use **different** `allow_nan` settings: **Container path (line 413):** ```python # Validate input_schema and capabilities (T2) before # delegating to the container executor so container-routed # tools receive the same spec validation as host-routed ones. try: json.dumps(inputs, allow_nan=False) # <-- STRICT: rejects NaN/Inf except (TypeError, ValueError) as exc: return ToolResult(...) ``` **Host path (line 463):** ```python # Validate that inputs are JSON-serialisable. Host-routed tools # use the default ``allow_nan=True`` for backward compatibility; # only the container path enforces RFC 7159 (P1-1). try: json.dumps(inputs) # <-- LENIENT: allow_nan defaults to True, accepts NaN/Inf except (TypeError, ValueError) as exc: return ToolResult(...) ``` The comment explicitly acknowledges this inconsistency ("backward compatibility") but this is the wrong place to be lenient — NaN and Infinity are not valid JSON per RFC 7159. When these values reach downstream consumers (LLM providers, databases, the audit log), they will fail to parse them, producing cryptic errors far removed from the source. Similarly, the **output** validation at line 507–515 also uses `allow_nan=True`: ```python try: json.dumps(raw_output) # allow_nan=True — NaN in output silently passes except (TypeError, ValueError) as exc: ... ``` ### Expected Behavior Both host and container paths should enforce RFC 7159-compliant JSON (`allow_nan=False`). If backward compatibility is required, a deprecation warning should be emitted rather than silently passing invalid values. ### Actual Behavior Tool inputs or outputs containing `float('nan')` or `float('inf')` are accepted by the host-path validation check, producing output like: ```json {"value": NaN} ``` which is not valid JSON and will cause `json.loads()` to raise `JSONDecodeError` in any RFC-compliant consumer. ### Suggested Fix Change both host-path `json.dumps()` calls to use `allow_nan=False`: ```python # Line 463 — input validation, host path try: json.dumps(inputs, allow_nan=False) # enforce RFC 7159 consistently except (TypeError, ValueError) as exc: return ToolResult( success=False, output={}, error=f"Inputs are not JSON-serialisable: {exc}", duration_ms=0.0, ) # Line 507 — output validation, host path try: json.dumps(raw_output, allow_nan=False) # enforce RFC 7159 consistently except (TypeError, ValueError) as exc: ... ``` ### Category `consistency` ### TDD Note After this bug issue is verified, a corresponding Type/Testing issue will be created for TDD. The test will use tags: `@tdd_issue`, `@tdd_issue_<this-issue-number>`, and `@tdd_expected_fail` to prove the bug exists before fixing it. --- **Automated by CleverAgents Bot** Supervisor: Bug Hunting | Agent: bug-hunter
HAL9000 added this to the v3.2.0 milestone 2026-04-09 21:52:44 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cleveragents/cleveragents-core#6582
No description provided.