Skip to content

Tool call JSON parser loses precision on large integer arguments (Discord snowflake IDs) #23170

Description

@BestJoester

Bug Description

When a model outputs a tool call with a large integer argument (e.g., a Discord channel ID like 1234567890123456789), the value silently loses precision during JSON parsing, resulting in a wrong value like 1234567890123456800.

This is because JSON.parse() converts numbers to JavaScript Number (IEEE 754 double), which only safely represents integers up to 2^53 - 1 (Number.MAX_SAFE_INTEGER = 9007199254740991). Discord snowflake IDs are 64-bit integers that regularly exceed this limit.

Reproduction

  1. Configure a cron job or subagent that sends a message to a Discord channel
  2. Use a local model (e.g., glm-4.7-flash-q6-k via llama-swap) that outputs the channel ID as a JSON number rather than a string
  3. The model generates the correct ID during streaming (visible in generation output), but the parsed tool call contains the wrong (rounded) value

Model output (correct):

{"action":"send","channel":"discord","target":1234567890123456789,"message":"..."}

Parsed result (wrong):

{"action":"send","channel":"discord","target":1234567890123456800,"message":"..."}

The last digits change due to float64 rounding.

Impact

  • Discord messages fail with "Unknown Channel" because the rounded ID doesn't exist
  • Affects any tool call argument containing a large integer (Discord IDs, Slack IDs, etc.)
  • Models that output IDs as strings (e.g., Claude) are unaffected, but this is model-dependent behavior
  • Local/open-source models are more likely to output bare numbers

Suggested Fix

The json-bigint package is already installed (node_modules/.pnpm/[email protected]). It could be used in the tool call argument parsing path to preserve large integers as strings.

Alternatively, a post-parse step could detect integers exceeding Number.MAX_SAFE_INTEGER and convert them to strings.

The relevant parsing happens in:

  • src/agents/ollama-stream.ts (lines ~262, ~271) — JSON.parse() on NDJSON response lines
  • Any other provider stream parsers that handle OpenAI-compatible tool call responses

Workaround

Instruct the model to always quote large IDs as strings in tool call arguments. This works but is fragile and model-dependent.

Environment

  • OpenClaw v2026.2.15
  • Provider: local (llama-swap, OpenAI-compatible API)
  • Model: glm-4.7-flash-q6-k
  • Node.js v22.22.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions