{"record":{"id":"e93e43c4ec9d8deb","repo":"chenhg5/cc-connect","slug":"pisession-marshal-command-w","errorCode":null,"errorMessage":"piSession: marshal command: %w","messagePattern":"piSession: marshal command: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"agent/pi/session.go","lineNumber":454,"sourceCode":"\t}\n\tsid := s.CurrentSessionID()\n\tevt := core.Event{Type: core.EventResult, SessionID: sid, Done: true}\n\tselect {\n\tcase s.events <- evt:\n\tcase <-s.ctx.Done():\n\t}\n\n\treturn nil\n}\n\n// writeRPCCommand marshals cmd as a single JSONL line and writes it to the\n// RPC process's stdin under rpcStdinMu. Used by both sendRPC (for \"prompt\"\n// commands during a turn) and startRPC (for the startup \"get_state\" probe\n// that fetches the session id before callers are released).\nfunc (s *piSession) writeRPCCommand(cmd map[string]any) error {\n\tb, err := json.Marshal(cmd)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"piSession: marshal command: %w\", err)\n\t}\n\tb = append(b, '\\n')\n\n\ts.rpcStdinMu.Lock()\n\t_, err = s.rpcStdin.Write(b)\n\ts.rpcStdinMu.Unlock()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"piSession: write stdin: %w\", err)\n\t}\n\treturn nil\n}\n\n// sendRPC writes a JSON \"prompt\" command to the persistent RPC process stdin.\n// Events are read asynchronously by readLoopRPC, including agent_end which\n// triggers EventResult.\n//\n// Issue #1723: image paths are embedded into the message text as\n// @<path> references (pi's standard mechanism, parsed the same way as in","sourceCodeStart":436,"sourceCodeEnd":472,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/pi/session.go#L436-L472","documentation":"agent/pi/session.go:454 — writeRPCCommand marshals the command map to JSON before writing it to the RPC stdin; if json.Marshal fails it returns \"piSession: marshal command: %w\". The commands built by this library (get_state probe, prompt commands) are plain map[string]any of JSON-safe values, so this nearly always indicates non-serializable data (channels, funcs, or invalid values like NaN) injected into the command payload — e.g. via prompt or attachment path content.","triggerScenarios":"writeRPCCommand is called by startRPC (get_state probe) and sendRPC (prompt commands); marshal fails when: (1) a value in the command map is not JSON-marshalable (chan, func, complex); (2) an unsupported value type slips in via extra args/attachment lists; (3) json.Marshal returns json.UnsupportedTypeError / UnsupportedValueError for float NaN/Inf.","commonSituations":"Custom code or a fork injecting non-JSON-safe fields into the prompt command; NaN/Inf values propagated into the payload; misuse of the internal API by plugin/extension code building commands with richer types.","solutions":["Inspect the wrapped json error (UnsupportedTypeError names the offending Go type) and remove/convert that value.","Sanitize payload values: ensure prompt text, image paths, and file paths are plain strings.","Replace NaN/Inf floats with strings or omit them from the command map.","If you maintain custom pi-agent code, validate the command with json.Marshal in a test before calling writeRPCCommand."],"exampleFix":"// before\ncmd := map[string]any{\"type\": \"prompt\", \"message\": msg, \"cb\": callback} // func not marshalable\n// after\ncmd := map[string]any{\"type\": \"prompt\", \"message\": msg}","handlingStrategy":"validation","validationCode":"func validateRPCCommand(cmd map[string]any) error {\n    if _, err := json.Marshal(cmd); err != nil {\n        return fmt.Errorf(\"command not JSON-serializable: %w\", err)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := validateRPCCommand(cmdMap); err != nil {\n    return fmt.Errorf(\"refusing to send invalid RPC command: %w\", err)\n}\nif err := writeRPCCommand(cmdMap); err != nil {\n    if strings.Contains(err.Error(), \"marshal command:\") {\n        slog.Error(\"RPC command marshal failed; sanitize payload\", \"err\", err)\n    }\n    return err\n}","preventionTips":["Keep RPC command payloads to JSON-safe types (string, number, bool, slice, map).","Never insert chan/func/complex values into command maps, even in internal tooling.","Convert NaN/Inf floats to strings or omit them.","Add a unit test that marshals every command variant the agent can emit."],"tags":["json","serialization","rpc","go","agent-pi"],"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"}