openclaw - ✅(Solved) Fix [Bug]: Agent incorrectly sets assistant message content to null when it is empty string, causing token validation error [1 pull requests, 2 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#43716Fetched 2026-04-08 00:17:14
View on GitHub
Comments
2
Participants
2
Timeline
10
Reactions
0
Author
Participants
Timeline (top)
commented ×2cross-referenced ×2labeled ×2referenced ×2

When using the /new command in OpenClaw webchat, the agent initiates a session startup sequence. It calls a tool to read SOUL.md, receives a response from the LLM (response1) with an empty string content and a tool call to read IDENTITY.md. However, when constructing the next request (request2), the agent converts the empty string content from the assistant message to null. This causes the LLM API to fail with the error:

text Messages token length must be in (0, 1048576], but got 0 because the message content is null. Manually changing the null to an empty string ("") in the request resolves the issue.

Error Message

When using the /new command in OpenClaw webchat, the agent initiates a session startup sequence. It calls a tool to read SOUL.md, receives a response from the LLM (response1) with an empty string content and a tool call to read IDENTITY.md. However, when constructing the next request (request2), the agent converts the empty string content from the assistant message to null. This causes the LLM API to fail with the error: 5. The API request fails with the token length validation error. The assistant message content is set to null, causing the API to reject the request with "Input Validation Error" because the token length is 0 (which is outside the allowed range). "error": "Messages token length must be in (0, 1048576], but got 0", "error_type": "Input Validation Error"

Root Cause

text Messages token length must be in (0, 1048576], but got 0 because the message content is null. Manually changing the null to an empty string ("") in the request resolves the issue.

Fix Action

Fixed

PR fix notes

PR #43733: Fix assistant tool-call replay content null regression

Description (problem / solution / changelog)

Summary

  • add an openai-completions payload wrapper that rewrites assistant content: null to "" when the assistant message contains tool calls
  • keep behavior scoped so only assistant tool-call replay turns are normalized
  • add regression tests covering both rewrite and no-rewrite cases

Validation

  • pnpm test src/agents/pi-embedded-runner-extraparams.test.ts (pass, 70 tests)

Closes #43716

Changed files

  • src/agents/pi-embedded-runner-extraparams.test.ts (modified, +77/-0)
  • src/agents/pi-embedded-runner/extra-params.ts (modified, +51/-0)

Code Example

Request1 (sent to LLM):
{
    "model": "deepseekv31",
    "messages": [
        {
            "role": "system",
            "content": "You are a personal assistant running inside OpenClaw..."
        },
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": "A new session was started via /new or /reset. Execute your Session Startup sequence now..."
                }
            ]
        },
        {
            "role": "assistant",
            "content": [
                {
                    "type": "text",
                    "text": "I'll start by reading the required files to understand who I am and who you are."
                }
            ],
            "tool_calls": [
                {
                    "id": "calllKQ4W10a",
                    "type": "function",
                    "function": {
                        "name": "read",
                        "arguments": "{\"path\":\"SOUL.md\"}"
                    }
                }
            ]
        },
        {
            "role": "tool",
            "content": "# SOUL.md - Who You Are...",
            "tool_call_id": "calllKQ4W10a"
        }
    ],
    "stream": true,
    "store": false,
    "max_completion_tokens": 8192,
    "tools": ["some tools description..."]
}
Response1 (from LLM):
{
    "id": "endpoint_common_323758",
    "object": "chat.completion",
    "created": 1773253544,
    "model": "deepseekv31",
    "choices": [
        {
            "index": 0,
            "message": {
                "role": "assistant",
                "content": "",
                "tool_calls": [
                    {
                        "id": "call_Qr7k3abw",
                        "type": "function",
                        "function": {
                            "name": "read",
                            "arguments": "{\"path\": \"IDENTITY.md\"}"
                        }
                    }
                ]
            },
            "finish_reason": "tool_calls"
        }
    ],
    "usage": {
        "prompt_tokens": 10181,
        "completion_tokens": 15,
        "total_tokens": 10196
    }
}
Request2 (constructed by agent):
{
    "model": "deepseekv31",
    "messages": [
        {
            "role": "system",
            "content": "You are a personal assistant running inside OpenClaw..."
        },
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": "A new session was started via /new or /reset. Execute your Session Startup sequence now..."
                }
            ]
        },
        {
            "role": "assistant",
            "content": [
                {
                    "type": "text",
                    "text": "I'll start by reading the required files to understand who I am and who you are."
                }
            ],
            "tool_calls": [
                {
                    "id": "calllKQ4W10a",
                    "type": "function",
                    "function": {
                        "name": "read",
                        "arguments": "{\"path\":\"SOUL.md\"}"
                    }
                }
            ]
        },
        {
            "role": "tool",
            "content": "# SOUL.md - Who You Are...",
            "tool_call_id": "calllKQ4W10a"
        },
        {
            "role": "assistant",
            "content": null,
            "tool_calls": [
                {
                    "id": "callQr7k3abw",
                    "type": "function",
                    "function": {
                        "name": "read",
                        "arguments": "{\"path\":\"IDENTITY.md\"}"
                    }
                }
            ]
        },
        {
            "role": "tool",
            "content": "# IDENTITY.md - Who I Am...",
            "tool_call_id": "callQr7k3abw"
        }
    ],
    "stream": true,
    "store": false,
    "max_completion_tokens": 8192,
    "tools": ["some tools description..."]
}
Response2 (from LLM):
{
  "error": "Messages token length must be in (0, 1048576], but got 0",
  "error_type": "Input Validation Error"
}
RAW_BUFFERClick to expand / collapse

Bug type

Regression (worked before, now fails)

Summary

When using the /new command in OpenClaw webchat, the agent initiates a session startup sequence. It calls a tool to read SOUL.md, receives a response from the LLM (response1) with an empty string content and a tool call to read IDENTITY.md. However, when constructing the next request (request2), the agent converts the empty string content from the assistant message to null. This causes the LLM API to fail with the error:

text Messages token length must be in (0, 1048576], but got 0 because the message content is null. Manually changing the null to an empty string ("") in the request resolves the issue.

Steps to reproduce

Steps to reproduce the behavior:

  1. Start a new session in OpenClaw webchat by sending /new.
  2. Observe that the agent first calls the read tool with path SOUL.md.
  3. The tool returns the content of SOUL.md, and the LLM responds with a message containing an empty content string and a tool call to read IDENTITY.md (response1).
  4. The agent then constructs the next API request (request2) and includes the assistant message from response1, but sets its content to null instead of keeping it as an empty string.
  5. The API request fails with the token length validation error.

Expected behavior

The assistant message content should remain an empty string ("") when constructing subsequent requests, not be converted to null. The API should accept the empty string and continue processing.

Actual behavior

The assistant message content is set to null, causing the API to reject the request with "Input Validation Error" because the token length is 0 (which is outside the allowed range).

OpenClaw version

2026.3.8

Operating system

windows 10

Install method

npm

Model

deepseek v3.1(openAI chat-compitable)

Provider / routing chain

deepseek v3.1

Config file / key location

No response

Additional provider/model setup details

No response

Logs, screenshots, and evidence

Request1 (sent to LLM):
{
    "model": "deepseekv31",
    "messages": [
        {
            "role": "system",
            "content": "You are a personal assistant running inside OpenClaw..."
        },
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": "A new session was started via /new or /reset. Execute your Session Startup sequence now..."
                }
            ]
        },
        {
            "role": "assistant",
            "content": [
                {
                    "type": "text",
                    "text": "I'll start by reading the required files to understand who I am and who you are."
                }
            ],
            "tool_calls": [
                {
                    "id": "calllKQ4W10a",
                    "type": "function",
                    "function": {
                        "name": "read",
                        "arguments": "{\"path\":\"SOUL.md\"}"
                    }
                }
            ]
        },
        {
            "role": "tool",
            "content": "# SOUL.md - Who You Are...",
            "tool_call_id": "calllKQ4W10a"
        }
    ],
    "stream": true,
    "store": false,
    "max_completion_tokens": 8192,
    "tools": ["some tools description..."]
}
Response1 (from LLM):
{
    "id": "endpoint_common_323758",
    "object": "chat.completion",
    "created": 1773253544,
    "model": "deepseekv31",
    "choices": [
        {
            "index": 0,
            "message": {
                "role": "assistant",
                "content": "",
                "tool_calls": [
                    {
                        "id": "call_Qr7k3abw",
                        "type": "function",
                        "function": {
                            "name": "read",
                            "arguments": "{\"path\": \"IDENTITY.md\"}"
                        }
                    }
                ]
            },
            "finish_reason": "tool_calls"
        }
    ],
    "usage": {
        "prompt_tokens": 10181,
        "completion_tokens": 15,
        "total_tokens": 10196
    }
}
Request2 (constructed by agent):
{
    "model": "deepseekv31",
    "messages": [
        {
            "role": "system",
            "content": "You are a personal assistant running inside OpenClaw..."
        },
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": "A new session was started via /new or /reset. Execute your Session Startup sequence now..."
                }
            ]
        },
        {
            "role": "assistant",
            "content": [
                {
                    "type": "text",
                    "text": "I'll start by reading the required files to understand who I am and who you are."
                }
            ],
            "tool_calls": [
                {
                    "id": "calllKQ4W10a",
                    "type": "function",
                    "function": {
                        "name": "read",
                        "arguments": "{\"path\":\"SOUL.md\"}"
                    }
                }
            ]
        },
        {
            "role": "tool",
            "content": "# SOUL.md - Who You Are...",
            "tool_call_id": "calllKQ4W10a"
        },
        {
            "role": "assistant",
            "content": null,
            "tool_calls": [
                {
                    "id": "callQr7k3abw",
                    "type": "function",
                    "function": {
                        "name": "read",
                        "arguments": "{\"path\":\"IDENTITY.md\"}"
                    }
                }
            ]
        },
        {
            "role": "tool",
            "content": "# IDENTITY.md - Who I Am...",
            "tool_call_id": "callQr7k3abw"
        }
    ],
    "stream": true,
    "store": false,
    "max_completion_tokens": 8192,
    "tools": ["some tools description..."]
}
Response2 (from LLM):
{
  "error": "Messages token length must be in (0, 1048576], but got 0",
  "error_type": "Input Validation Error"
}

Impact and severity

No response

Additional information

No response

extent analysis

Fix Plan

To fix the issue, we need to ensure that the content field in the assistant message is not converted to null when it's an empty string. We can achieve this by adding a simple check before constructing the Request2 object.

  • Check if the content field is an empty string and set it to an empty string explicitly instead of null.
  • Update the code that constructs the Request2 object to include this check.

Example code snippet:

if (response1.choices[0].message.content === "") {
    request2.messages.push({
        "role": "assistant",
        "content": "", // Set content to empty string explicitly
        "tool_calls": response1.choices[0].message.tool_calls
    });
} else {
    request2.messages.push({
        "role": "assistant",
        "content": response1.choices[0].message.content,
        "tool_calls": response1.choices[0].message.tool_calls
    });
}

Verification

To verify that the fix worked, you can:

  • Send a new request to the LLM API with the updated Request2 object.
  • Check the response from the LLM API to ensure that it no longer returns an "Input Validation Error".
  • Verify that the content field in the assistant message is an empty string instead of null.

Extra Tips

  • Make sure to update the code that constructs the Request2 object to include the check for empty strings.
  • Consider adding additional logging or debugging statements to ensure that the fix is working as expected.
  • If you're using a library or framework to construct the Request2 object, check the documentation to see if there are any built-in features or options that can help prevent this issue.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

The assistant message content should remain an empty string ("") when constructing subsequent requests, not be converted to null. The API should accept the empty string and continue processing.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING