chenhg5/cc-connect · error
codex app-server encode: %w
Error message
codex app-server encode: %w
What it means
`writeJSON` marshals the JSON-RPC payload with `json.Marshal`; if that fails it returns `codex app-server encode: %w`. For payloads built from `map[string]any` holding normal strings/numbers this is nearly impossible, so it usually signals a caller-supplied value containing unmarshalable data (channels, funcs, NaN floats, cyclic structures).
Source
Thrown at agent/codex/appserver_session.go:1731
}
s.procMu.Unlock()
}
func (s *appServerSession) notify(method string, params any) error {
payload := map[string]any{
"jsonrpc": "2.0",
"method": method,
}
if params != nil {
payload["params"] = params
}
return s.writeJSON(payload)
}
func (s *appServerSession) writeJSON(v any) error {
b, err := json.Marshal(v)
if err != nil {
return fmt.Errorf("codex app-server encode: %w", err)
}
s.procMu.Lock()
stdin := s.stdin
s.procMu.Unlock()
if stdin == nil {
return fmt.Errorf("codex app-server connection is closed")
}
s.writeMu.Lock()
defer s.writeMu.Unlock()
if _, err := stdin.Write(append(b, '\n')); err != nil {
return fmt.Errorf("codex app-server write: %w", err)
}
return nil
}
View on GitHub (pinned to 4000b2338a)
Solutions
- Inspect the params value passed to the failing call for NaN/Inf floats or non-serializable types.
- Sanitize user options before passing them into session requests (only string maps allowed).
- Add a dry-run `json.Marshal(params)` in tests to catch this early.
- Ensure numeric values derived from usage/rate data are checked with math.IsNaN/IsInf before use.
Example fix
// before: pass through raw float from external data
params := map[string]any{"tokens": usage.Ratio} // may be NaN
// after: sanitize
if math.IsNaN(usage.Ratio) || math.IsInf(usage.Ratio, 0) {
usage.Ratio = 0
}
params := map[string]any{"tokens": usage.Ratio} Defensive patterns
Strategy: validation
Validate before calling
// validate params are marshalable before sending
func validateParams(params any) error {
_, err := json.Marshal(params)
return err
}
// call before request()/notify() Type guard
func isMarshalable(v any) bool {
rv := reflect.ValueOf(v)
switch rv.Kind() {
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
return false
case reflect.Float64, reflect.Float32:
f := rv.Float()
return !math.IsNaN(f) && !math.IsInf(f, 0)
}
return true
} Try / catch
if err := sess.notify(method, params); err != nil {
var encErr *json.UnsupportedTypeError
if errors.As(err, &encErr) || strings.Contains(err.Error(), "encode") {
slog.Error("unmarshalable params", "method", method, "err", err)
}
return err
} Prevention
- Sanitize user-supplied option maps (strings/numbers only) before they reach request params.
- Guard computed floats with math.IsNaN/IsInf.
- Unit-test json.Marshal on all request payload builders.
- Avoid passing raw external data structures into JSON-RPC params.
When it happens
Trigger: Calling `request`, `requestWithTimeout`, or `notify` with params containing a value json.Marshal cannot encode: NaN/Inf floats, channels, funcs, or cyclic references in options maps.
Common situations: User-supplied `options["env"]`/`args` maps carrying exotic values propagated into request params; floats computed from usage stats that became NaN; a bug passing a non-serializable type as params.
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
- marshal Agy permission hook: %w
- marshal Agy hooks overlay: %w
- marshal stdin: %w
- marshal: %w
- decode %s response: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/f67e9cceeecad2d8.
Report an issue: GitHub.