Skip to content

OpenRouter: empty tool arguments serialized as JSON array instead of object #926

Description

@timkley

Bug Description

When using the OpenRouter provider with an Anthropic model (e.g. anthropic/claude-sonnet-4.6), multi-step tool calls fail with:

OpenRouter Bad Request: messages.3.content.3.tool_use.input: Input should be a valid dictionary

This happens when a tool is called with no arguments (empty {}).

Root Cause

In src/Providers/OpenRouter/Maps/MessageMap.php:162, tool call arguments are serialized as:

'arguments' => json_encode($toolCall->arguments()),

When a tool has no arguments:

  1. $toolCall->arguments() returns [] (PHP empty array)
  2. json_encode([]) produces "[]" (JSON array)
  3. OpenRouter translates this to Anthropic's input: []
  4. Anthropic rejects it because input must be a dictionary (object), not an array

This is a PHP limitation — json_decode("{}", true) returns [], and json_encode([]) returns "[]" instead of "{}".

The Anthropic Provider Already Handles This

The Anthropic provider in src/Providers/Anthropic/Maps/MessageMap.php:163 correctly handles this case:

'input' => $toolCall->arguments() === [] ? new \stdClass : $toolCall->arguments(),

The OpenRouter provider is missing this safeguard.

Reproduction

  1. Configure Prism with OpenRouter provider routing to an Anthropic model
  2. Register a tool that accepts no required arguments (e.g. a "list all users" tool)
  3. Send a prompt that triggers the tool, then requires a follow-up step (multi-step tool use)
  4. The second API call fails because the accumulated assistant message contains "arguments": "[]" instead of "arguments": "{}"

Suggested Fix

In src/Providers/OpenRouter/Maps/MessageMap.php, change:

'arguments' => json_encode($toolCall->arguments()),

To:

'arguments' => json_encode($toolCall->arguments() === [] ? new \stdClass : $toolCall->arguments()),

This matches the existing pattern in the Anthropic provider.

Note: The same issue likely exists in other providers that use json_encode($toolCall->arguments()):

  • src/Providers/XAI/Maps/MessageMap.php
  • src/Providers/Mistral/Maps/MessageMap.php
  • src/Providers/Groq/Maps/MessageMap.php
  • src/Providers/DeepSeek/Maps/MessageMap.php

We'd be happy to provide a PR for this fix.

Environment

  • prism-php/prism: v0.99.19
  • laravel/ai: ^0.1.3
  • PHP: 8.4
  • Provider: OpenRouter → anthropic/claude-sonnet-4.6

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions