hermes - 💡(How to fix) Fix cross-provider poisoned history: reasoning_content from thinking-mode sessions causes HTTP 400 on Cerebras and other strict providers

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…

When a Hermes session previously used a thinking-mode provider (DeepSeek / Kimi / MiMo), those assistant messages get reasoning_content stored in the session DB. Switching to a provider that does not support reasoning_content echo-back (e.g. Cerebras gpt-oss-120b, Mistral, Fireworks) causes an immediate HTTP 400 on the first API call that replays that history.

Error Message

messages.2.assistant.reasoning_content: property 'messages.2.assistant.reasoning_content' is unsupported
{'type': 'invalid_request_error', 'param': 'validation_error', 'code': 'wrong_api_format'}

Non-retryable. Hermes aborts.

Root Cause

copy_reasoning_content_for_api in agent/agent_runtime_helpers.py copies reasoning_content onto the API message unconditionally:

  • Step 1 (line ~1940): when source_msg["reasoning_content"] is a string, it is copied to api_msg with no provider gate.
  • Step 3 (line ~1972): when source_msg["reasoning"] is a string, it is promoted to api_msg["reasoning_content"] with no provider gate.

Both call sites do api_msg = msg.copy() first, so api_msg already carries reasoning_content from the shallow copy before the function runs. There is no code path that strips it when _needs_thinking_reasoning_pad() is False.

For reference, reapply_reasoning_echo_for_provider already has the correct guard:

if not agent._needs_thinking_reasoning_pad():
    return 0

copy_reasoning_content_for_api does not.

Fix Action

Fix / Workaround

  1. Same-session: the active provider is itself a reasoning model (e.g. gpt-oss-120b returns reasoning_content), which poisons history for the next turn. Config workaround: reasoning_effort: '' in config.yaml prevents the model from emitting it.
  2. Cross-session: a prior session used DeepSeek/Kimi/MiMo; the current session switches to a strict provider. No config workaround — requires the code fix.

Code Example

messages.2.assistant.reasoning_content: property 'messages.2.assistant.reasoning_content' is unsupported
{'type': 'invalid_request_error', 'param': 'validation_error', 'code': 'wrong_api_format'}

---

if not agent._needs_thinking_reasoning_pad():
    return 0

---

if not agent._needs_thinking_reasoning_pad():
    api_msg.pop("reasoning_content", None)
    return
RAW_BUFFERClick to expand / collapse

Summary

When a Hermes session previously used a thinking-mode provider (DeepSeek / Kimi / MiMo), those assistant messages get reasoning_content stored in the session DB. Switching to a provider that does not support reasoning_content echo-back (e.g. Cerebras gpt-oss-120b, Mistral, Fireworks) causes an immediate HTTP 400 on the first API call that replays that history.

Error

messages.2.assistant.reasoning_content: property 'messages.2.assistant.reasoning_content' is unsupported
{'type': 'invalid_request_error', 'param': 'validation_error', 'code': 'wrong_api_format'}

Non-retryable. Hermes aborts.

Root cause

copy_reasoning_content_for_api in agent/agent_runtime_helpers.py copies reasoning_content onto the API message unconditionally:

  • Step 1 (line ~1940): when source_msg["reasoning_content"] is a string, it is copied to api_msg with no provider gate.
  • Step 3 (line ~1972): when source_msg["reasoning"] is a string, it is promoted to api_msg["reasoning_content"] with no provider gate.

Both call sites do api_msg = msg.copy() first, so api_msg already carries reasoning_content from the shallow copy before the function runs. There is no code path that strips it when _needs_thinking_reasoning_pad() is False.

For reference, reapply_reasoning_echo_for_provider already has the correct guard:

if not agent._needs_thinking_reasoning_pad():
    return 0

copy_reasoning_content_for_api does not.

Proposed fix

Add an early guard in copy_reasoning_content_for_api after the role check:

if not agent._needs_thinking_reasoning_pad():
    api_msg.pop("reasoning_content", None)
    return

This:

  • Pops the field (not just skips adding — msg.copy() already injected it)
  • Covers both step-1 and step-3 leak paths in one place
  • Mirrors the identical early-return already in reapply_reasoning_echo_for_provider
  • Leaves all DeepSeek / Kimi / MiMo echo logic unchanged (guard is skipped for them)

Two variants of this bug

  1. Same-session: the active provider is itself a reasoning model (e.g. gpt-oss-120b returns reasoning_content), which poisons history for the next turn. Config workaround: reasoning_effort: '' in config.yaml prevents the model from emitting it.
  2. Cross-session: a prior session used DeepSeek/Kimi/MiMo; the current session switches to a strict provider. No config workaround — requires the code fix.

Affected file

agent/agent_runtime_helpers.pycopy_reasoning_content_for_api

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…

Still need to ship something?

×6

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

Back to top recommendations

TRENDING

hermes - 💡(How to fix) Fix cross-provider poisoned history: reasoning_content from thinking-mode sessions causes HTTP 400 on Cerebras and other strict providers