Skip to content

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

@BestJoester

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/json-bigint@1.0.0). 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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions