chenhg5/cc-connect · error
marshal: %w
Error message
marshal: %w
What it means
The lspWriter failed to JSON-marshal a JSON-RPC message (request, notification, response, or error) before framing it with Content-Length. json.Marshal fails only for unsupported types (channels, funcs, cyclic structures), so this indicates a bug in message construction rather than environment issues.
Source
Thrown at agent/copilot/jsonrpc.go:61
func (e *jsonRPCError) Error() string {
return fmt.Sprintf("JSON-RPC error %d: %s", e.Code, e.Message)
}
// lspWriter writes Content-Length framed JSON-RPC messages.
type lspWriter struct {
w io.Writer
mu sync.Mutex
}
func newLSPWriter(w io.Writer) *lspWriter {
return &lspWriter{w: w}
}
func (lw *lspWriter) writeMessage(v any) error {
data, err := json.Marshal(v)
if err != nil {
return fmt.Errorf("marshal: %w", err)
}
header := fmt.Sprintf("Content-Length: %d\r\n\r\n", len(data))
lw.mu.Lock()
defer lw.mu.Unlock()
if _, err := io.WriteString(lw.w, header); err != nil {
return fmt.Errorf("write header: %w", err)
}
if _, err := lw.w.Write(data); err != nil {
return fmt.Errorf("write body: %w", err)
}
return nil
}
// lspReader reads Content-Length framed JSON-RPC messages.
type lspReader struct {View on GitHub (pinned to 4000b2338a)
Solutions
- Inspect the value being marshaled in the failing call and remove/replace non-marshalable fields
- Add json:"-" tags to fields that must not be serialized
- Convert custom types to plain serializable structs/maps before calling call/notify
- Add a unit test marshaling every JSON-RPC message type the agent sends
Example fix
// before
type deleteParams struct {
SessionID string `json:"sessionId"`
onClose func() // not marshalable
}
// after
type deleteParams struct {
SessionID string `json:"sessionId"`
onClose func() `json:"-"`
} Defensive patterns
Strategy: validation
Validate before calling
// guard helper for JSON-RPC payloads
func mustMarshalable(v any) error {
var b bytes.Buffer
enc := json.NewEncoder(&b)
if err := enc.Encode(v); err != nil { return fmt.Errorf("unmarshalable rpc payload: %w", err) }
return nil
} Try / catch
if err := rpc.call(ctx, method, params); err != nil && strings.Contains(err.Error(), "marshal:") {
slog.Error("non-serializable RPC payload — bug in params construction", "method", method, "err", err)
} Prevention
- Keep JSON-RPC params structs free of funcs/chans/mutexes; tag internal fields json:"-"
- Add round-trip tests marshaling every outbound request type
- Use plain maps/DTOs at the RPC boundary
When it happens
Trigger: call/notify/respond/writeResponse/writeError passing a params or result value containing a non-marshalable type (chan, func, or a reference cycle) to writeMessage.
Common situations: After a code change introducing a custom params type with unsupported fields (e.g. sync.Mutex captured by value, func field, cyclic pointer graph).
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: %w
- piSession: marshal command: %w
- piSession: marshal extension_ui_response: %w
- mimo tts: marshal request: %w
- marshal payload: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/3ad632519fed71e3.
Report an issue: GitHub.