{"record":{"id":"f67e9cceeecad2d8","repo":"chenhg5/cc-connect","slug":"codex-app-server-encode-w","errorCode":null,"errorMessage":"codex app-server encode: %w","messagePattern":"codex app-server encode: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/codex/appserver_session.go","lineNumber":1731,"sourceCode":"\t}\n\ts.procMu.Unlock()\n}\n\nfunc (s *appServerSession) notify(method string, params any) error {\n\tpayload := map[string]any{\n\t\t\"jsonrpc\": \"2.0\",\n\t\t\"method\":  method,\n\t}\n\tif params != nil {\n\t\tpayload[\"params\"] = params\n\t}\n\treturn s.writeJSON(payload)\n}\n\nfunc (s *appServerSession) writeJSON(v any) error {\n\tb, err := json.Marshal(v)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"codex app-server encode: %w\", err)\n\t}\n\n\ts.procMu.Lock()\n\tstdin := s.stdin\n\ts.procMu.Unlock()\n\tif stdin == nil {\n\t\treturn fmt.Errorf(\"codex app-server connection is closed\")\n\t}\n\n\ts.writeMu.Lock()\n\tdefer s.writeMu.Unlock()\n\tif _, err := stdin.Write(append(b, '\\n')); err != nil {\n\t\treturn fmt.Errorf(\"codex app-server write: %w\", err)\n\t}\n\treturn nil\n}\n","sourceCodeStart":1713,"sourceCodeEnd":1748,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/codex/appserver_session.go#L1713-L1748","documentation":"`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).","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: pass through raw float from external data\nparams := map[string]any{\"tokens\": usage.Ratio} // may be NaN\n\n// after: sanitize\nif math.IsNaN(usage.Ratio) || math.IsInf(usage.Ratio, 0) {\n    usage.Ratio = 0\n}\nparams := map[string]any{\"tokens\": usage.Ratio}","handlingStrategy":"validation","validationCode":"// validate params are marshalable before sending\nfunc validateParams(params any) error {\n    _, err := json.Marshal(params)\n    return err\n}\n// call before request()/notify()","typeGuard":"func isMarshalable(v any) bool {\n    rv := reflect.ValueOf(v)\n    switch rv.Kind() {\n    case reflect.Chan, reflect.Func, reflect.UnsafePointer:\n        return false\n    case reflect.Float64, reflect.Float32:\n        f := rv.Float()\n        return !math.IsNaN(f) && !math.IsInf(f, 0)\n    }\n    return true\n}","tryCatchPattern":"if err := sess.notify(method, params); err != nil {\n    var encErr *json.UnsupportedTypeError\n    if errors.As(err, &encErr) || strings.Contains(err.Error(), \"encode\") {\n        slog.Error(\"unmarshalable params\", \"method\", method, \"err\", err)\n    }\n    return err\n}","preventionTips":["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."],"tags":["codex","json","marshal","serialization"],"backgroundTag":"json-marshal-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}