chenhg5/cc-connect · error
encode rpc message: %w
Error message
encode rpc message: %w
What it means
writeRPCMessage marshals an outgoing JSON-RPC payload (params or notification) with encoding/json and failed, returning a wrapped "encode rpc message" error. Marshal only fails for values the JSON encoder cannot represent (channels, funcs, cyclic structures, or invalid types like NaN in float fields), so this points to a bad payload constructed before the call.
Source
Thrown at agent/codex/session.go:779
}
}
return nil
}
}
func rpcNotifyOverIO(stdin io.Writer, method string, params any) error {
payload := map[string]any{
"jsonrpc": "2.0",
"method": method,
"params": params,
}
return writeRPCMessage(stdin, payload)
}
func writeRPCMessage(w io.Writer, payload any) error {
b, err := json.Marshal(payload)
if err != nil {
return fmt.Errorf("encode rpc message: %w", err)
}
if _, err := w.Write(append(b, '\n')); err != nil {
return fmt.Errorf("write rpc message: %w", err)
}
return nil
}
// RespondPermission is a no-op for Codex — permissions are handled via CLI flags.
func (cs *codexSession) RespondPermission(_ string, _ core.PermissionResult) error {
return nil
}
func (cs *codexSession) Events() <-chan core.Event {
return cs.events
}
func (cs *codexSession) CurrentSessionID() string {
v, _ := cs.threadID.Load().(string)View on GitHub (pinned to 4000b2338a)
Solutions
- Inspect the payload type being passed to rpcRequestOverIO/rpcNotifyOverIO and ensure all fields are JSON-serializable.
- Check for NaN/Inf float values or cyclic references introduced by recent code changes.
- Validate the marshaling with a small test: `json.Marshal(params)` and inspect the error text, which names the offending Go type.
- Upgrade or downgrade to a matching connector/codex version combination if this started after an update (struct drift).
Example fix
// before: unmarshalable field
params := struct{ At time.Time }{At: time.Now()} // ok, but ensure no channels/funcs
// after: verify serialization before send
if _, err := json.Marshal(params); err != nil {
return fmt.Errorf("codex: invalid rpc params: %w", err)
} Defensive patterns
Strategy: validation
Validate before calling
// validate payload serializability before sending
if _, err := json.Marshal(payload); err != nil {
return fmt.Errorf("rpc payload not JSON-serializable: %w", err)
} Type guard
func isMarshalable(v any) bool {
_, err := json.Marshal(v)
return err == nil
} Try / catch
err := rpcNotifyOverIO(stdin, ctx, "initialized")
if err != nil && strings.Contains(err.Error(), "encode rpc message") {
slog.Error("rpc payload contains unmarshalable values", "err", err)
// fix payload construction; a retry with the same payload will fail identically
} Prevention
- Keep RPC param structs limited to JSON-safe types (no channels, funcs, or cycles)
- Guard against NaN/Inf floats in numeric parameters
- Add a unit test marshaling every params type used in RPC calls
- Let encoding/json tag hygiene (`json:"..."`) define the wire contract explicitly
When it happens
Trigger: json.Marshal(payload) returns an error inside writeRPCMessage, called from rpcRequestOverIO or rpcNotifyOverIO when sending a request/notification to the codex app-server.
Common situations: A params struct gained an unsupported field type (e.g. json.Number misuse, cyclic pointer graph); NaN/Inf floats in numeric options; passing an unsupported value type as a param.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- codex app-server resume returned empty thread id
- codex app-server start returned empty thread id
- codex app-server turn/start: %w
- turn failed (no details)
- %s
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/4fb2d701845bd21d.
Report an issue: GitHub.