Client or integration
Codex CLI
Provider or upstream service
xAI (xai/grok-4.5)
OpenCodex version
dev at 3982dae47 (observed live on the running service, 2.13.0)
Endpoint or capability
/v1/responses routed tool calls — integer tool arguments
Current behaviour
Grok serializes integer tool-call arguments as floats, and OpenCodex forwards the string through untouched. Codex then rejects the call before it ever runs, because its tool schemas declare those fields as integer types.
Every failure looks like this, and the tool never executes:
failed to parse function arguments: invalid type: floating point `120000.0`, expected u64
failed to parse function arguments: invalid type: floating point `29356.0`, expected i32
failed to parse function arguments: invalid type: floating point `12000.0`, expected usize
The .0 is present in the assembled arguments string that reaches the client, not something the client introduces. Extracted from a session rollout:
exec_command -> ["yield_time_ms":120000.0]
exec_command -> ["yield_time_ms":120000.0]
write_stdin -> ["session_id":29356.0, "yield_time_ms":60000.0]
write_stdin -> ["session_id":29356.0]
The model's intent is an integer in every case: yield_time_ms is a millisecond budget, and session_id is an exec session handle that was itself issued as 29356. Grok is round-tripping them through a float representation and emitting 29356.0.
This is not a JSON round-trip artifact inside OpenCodex. JSON.stringify(JSON.parse(...)) preserves integers exactly:
$ bun -e 'console.log(JSON.stringify(JSON.parse(String.raw`{"session_id":29356,"yield_time_ms":120000}`)))'
{"session_id":29356,"yield_time_ms":120000}
So the .0 arrives from upstream and survives because nothing on the routed path normalizes it. parseArgsObj in src/bridge.ts:246 only decides whether the arguments parse as an object; it does not reconcile argument values against the declared tool schema, and there is no integer coercion anywhere in src/adapters/ for tool-call arguments.
Expected behaviour
A float-valued argument whose declared schema type is integer should reach the client as an integer when the value is integral (Number.isInteger(120000.0) is true), so the tool call runs.
A non-integral value for an integer field is a genuine upstream error and should stay an error rather than being silently truncated.
Impact
Every affected turn is a hard failure, not a degradation: the tool call is rejected before execution, so the model loses the result and typically retries the same call with the same float. In the captured session this consumed five consecutive tool calls across exec_command and write_stdin without a single one running.
It is also transport-visible only on routed providers. The same Codex client works when the model emits real integers, which is why this reads as a Grok-specific tool-calling failure rather than a client bug.
Minimal redacted request or reproduction
- Route Codex CLI through OpenCodex at
xai/grok-4.5.
- Ask for work that makes the model call a tool with an integer argument — any
exec_command where it chooses a yield_time_ms, or any write_stdin reusing a session_id.
- Observe the
function_call_output for that call.
Observed: failed to parse function arguments: invalid type: floating point 120000.0, expected u64, and the command does not run.
Expected: the call executes.
Scope check
Occurrences in local session rollouts are xai/grok-4.5 only. Five distinct values across two tool names (exec_command, write_stdin) and four Rust integer types (u64, i64, i32, usize), which is consistent with a serializer-level behavior on the provider side rather than one bad tool schema.
I have not verified whether other xAI models or other providers do the same; the sample here is one provider.
Logs or error output
{"type":"function_call_output","output":"failed to parse function arguments: invalid type: floating point `120000.0`, expected u64 at line 1 column 310"}
{"type":"function_call_output","output":"failed to parse function arguments: invalid type: floating point `120000.0`, expected u64 at line 1 column 305"}
{"type":"function_call_output","output":"failed to parse function arguments: invalid type: floating point `29356.0`, expected i32"}
Checks
Client or integration
Codex CLI
Provider or upstream service
xAI (
xai/grok-4.5)OpenCodex version
devat3982dae47(observed live on the running service, 2.13.0)Endpoint or capability
/v1/responsesrouted tool calls — integer tool argumentsCurrent behaviour
Grok serializes integer tool-call arguments as floats, and OpenCodex forwards the string through untouched. Codex then rejects the call before it ever runs, because its tool schemas declare those fields as integer types.
Every failure looks like this, and the tool never executes:
The
.0is present in the assembled arguments string that reaches the client, not something the client introduces. Extracted from a session rollout:The model's intent is an integer in every case:
yield_time_msis a millisecond budget, andsession_idis an exec session handle that was itself issued as29356. Grok is round-tripping them through a float representation and emitting29356.0.This is not a JSON round-trip artifact inside OpenCodex.
JSON.stringify(JSON.parse(...))preserves integers exactly:So the
.0arrives from upstream and survives because nothing on the routed path normalizes it.parseArgsObjinsrc/bridge.ts:246only decides whether the arguments parse as an object; it does not reconcile argument values against the declared tool schema, and there is no integer coercion anywhere insrc/adapters/for tool-call arguments.Expected behaviour
A float-valued argument whose declared schema type is
integershould reach the client as an integer when the value is integral (Number.isInteger(120000.0)is true), so the tool call runs.A non-integral value for an integer field is a genuine upstream error and should stay an error rather than being silently truncated.
Impact
Every affected turn is a hard failure, not a degradation: the tool call is rejected before execution, so the model loses the result and typically retries the same call with the same float. In the captured session this consumed five consecutive tool calls across
exec_commandandwrite_stdinwithout a single one running.It is also transport-visible only on routed providers. The same Codex client works when the model emits real integers, which is why this reads as a Grok-specific tool-calling failure rather than a client bug.
Minimal redacted request or reproduction
xai/grok-4.5.exec_commandwhere it chooses ayield_time_ms, or anywrite_stdinreusing asession_id.function_call_outputfor that call.Observed:
failed to parse function arguments: invalid type: floating point120000.0, expected u64, and the command does not run.Expected: the call executes.
Scope check
Occurrences in local session rollouts are
xai/grok-4.5only. Five distinct values across two tool names (exec_command,write_stdin) and four Rust integer types (u64,i64,i32,usize), which is consistent with a serializer-level behavior on the provider side rather than one bad tool schema.I have not verified whether other xAI models or other providers do the same; the sample here is one provider.
Logs or error output
Checks