chenhg5/cc-connect · warning
googlechat: marshal body: %w
Error message
googlechat: marshal body: %w
What it means
buildSendRequest serializes the Chat message payload ({"text": ...} plus thread fields) to JSON before posting. json.Marshal of this fixed-shape map should never fail in practice (no channels, funcs, or unsupported types are placed in it), so this error indicates an internal invariant violation rather than a caller mistake. Callers (post, tests, SendPreviewStart) receive "" URL and nil body alongside the wrapped error.
Source
Thrown at platform/googlechat/googlechat.go:394
return u
}
// applyThread adds the thread field to body when rc has a thread.
func applyThread(body map[string]any, rc replyContext) {
if rc.thread != "" {
body["thread"] = map[string]any{"name": rc.thread}
}
}
// buildSendRequest builds the Chat REST API URL and JSON body to post content
// into rc's space. When a thread is known the reply is threaded (falling back
// to a new thread if that thread no longer accepts replies).
func buildSendRequest(rc replyContext, content string) (string, []byte, error) {
body := map[string]any{"text": content}
applyThread(body, rc)
b, err := json.Marshal(body)
if err != nil {
return "", nil, fmt.Errorf("googlechat: marshal body: %w", err)
}
return messageURL(rc), b, nil
}
// doRequest executes req using botClient and returns the response on success.
// On non-2xx it reads the error body, closes it, and returns an error.
// The caller is responsible for draining and closing resp.Body on success.
func (p *Platform) doRequest(req *http.Request) (*http.Response, error) {
resp, err := p.botClient.Do(req)
if err != nil {
return nil, err
}
if resp.StatusCode >= 300 {
return nil, httpErrorBody(resp, fmt.Sprintf("googlechat: %s %s", req.Method, req.URL.Path))
}
return resp, nil
}
View on GitHub (pinned to 4000b2338a)
Solutions
- If it appears, inspect any recent changes to buildSendRequest/applyThread that added new body fields
- Ensure all values placed in the body map are JSON-serializable types (string, number, bool, nested maps/slices)
- Report as a bug with the wrapped inner error message if hit on a released binary
Example fix
// before body["cards"] = someFunc // not JSON-marshalable // after body["cards"] = renderedCardMap // plain map[string]any
Defensive patterns
Strategy: try-catch
Type guard
func isReplyContext(v any) bool { _, ok := v.(replyContext); return ok } Try / catch
url, body, err := buildSendRequest(rc, content)
if err != nil {
return fmt.Errorf("googlechat: build payload: %w", err) // internal bug; report
} Prevention
- Only put JSON-serializable values (string, number, bool, map, slice) into the send body map
- Add a unit test asserting buildSendRequest succeeds for all reply-context shapes
- Treat occurrences as an internal bug to report, not a config issue
When it happens
Trigger: Effectively only reachable if map values become non-marshalable (e.g. a future code change inserts a func or channel into the body map); not triggerable from configuration or normal API usage today.
Common situations: Encountered only during development/refactoring of buildSendRequest or applyThread when unusual values are added to the payload map.
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
- googlechat: invalid reply context type %T
- googlechat: upload: encode metadata: %w
- googlechat: upload: decode response: %w
- googlechat: marshal attachment body: %w
- googlechat: parse create response: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/dc5650ce5e53f53e.
Report an issue: GitHub.