NousResearch/hermes-agent · error · CodexAppServerError
-32603
-32603
Error message
codex thread/start returned no thread id (payload keys: {sorted(result.keys())}) What it means
CodexAppServerError (code -32603, internal error) from the thread/start handling in agent/transports/codex_app_server_session.py:359. The session layer tolerates several codex serialization variants (thread.id, thread.sessionId, top-level sessionId, threadId) but if none of them yields an id it refuses to continue, reporting which keys the payload actually had so the mismatch is diagnosable.
Source
Thrown at agent/transports/codex_app_server_session.py:359
# configured otherwise in their codex config.toml) is the standard
# codex CLI workflow and avoids fighting codex's own validation.
# Users who want a write-capable profile configure it in their
# ~/.codex/config.toml the same way they would for any codex usage.
params: dict[str, Any] = {"cwd": self._cwd}
result = self._client.request("thread/start", params, timeout=15)
# Cross-fill thread.id/sessionId — different codex versions have
# serialized this under either key. Mirrors openclaw beta.8's
# tolerance fix so future codex drops/renames don't KeyError us
# at handshake time.
thread_obj = result.get("thread") or {}
thread_id = (
thread_obj.get("id")
or thread_obj.get("sessionId")
or result.get("sessionId")
or result.get("threadId")
)
if not thread_id:
raise CodexAppServerError(
code=-32603,
message=(
"codex thread/start returned no thread id "
f"(payload keys: {sorted(result.keys())})"
),
)
self._thread_id = thread_id
logger.info(
"codex app-server thread started: id=%s profile=%s cwd=%s",
self._thread_id[:8],
self._permission_profile,
self._cwd,
)
return self._thread_id
def close(self) -> None:
if self._closed:
returnView on GitHub (pinned to c896c09c42)
Solutions
- Read the payload keys in the message and compare against the four tolerated keys (id/sessionId/threadId) to confirm the schema moved.
- Pin the codex app-server to a version this client is tested against (or upgrade hermes-agent to a release supporting the new schema).
- If you maintain a fork, add the new key to the cross-fill chain in codex_app_server_session.py and upstream it.
- Check codex's own logs for why thread/start may have returned a degenerate payload (e.g. auth/config error).
Example fix
# before (tolerated keys only)
thread_id = (
thread_obj.get("id") or thread_obj.get("sessionId")
or result.get("sessionId") or result.get("threadId")
)
# after (extend for a newer codex schema)
thread_id = (
thread_obj.get("id") or thread_obj.get("sessionId")
or result.get("sessionId") or result.get("threadId")
or result.get("conversationId")
) Defensive patterns
Strategy: try-catch
Validate before calling
_TOLERATED_KEYS = ("thread", "sessionId", "threadId")
def thread_start_payload_looks_ok(result: dict) -> bool:
t = result.get("thread") or {}
return bool(t.get("id") or t.get("sessionId") or result.get("sessionId") or result.get("threadId")) Try / catch
from agent.transports.codex_app_server import CodexAppServerError
try:
session.start_thread()
except CodexAppServerError as exc:
if exc.code == -32603 and "no thread id" in exc.message:
raise RuntimeError(
f"codex schema mismatch (keys: {exc.message}); pin/upgrade codex"
) from exc
raise Prevention
- Pin codex to a version tested with this client.
- Include the payload-keys detail from the message in bug reports.
- After any codex upgrade, smoke-test thread/start before rolling out.
When it happens
Trigger: A codex app-server version whose thread/start response schema moved the thread id to a new key not in the tolerated list (or omits it entirely on failure), typically right after upgrading/downgrading codex.
Common situations: Version skew: the pinned codex version changed its JSON-RPC payload shape; a partially-failed thread/start that returns an error-ish dict without an id; nightly/rolling codex installs.
Related errors
- already initialized
- codex app-server method {method!r} timed out after {timeout}
- codex app-server error {code}: {message}
- codex app-server client is closed
- codex app-server stdin not available
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/cb98b1f895871c78.
Report an issue: GitHub.