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

  1. If it appears, inspect any recent changes to buildSendRequest/applyThread that added new body fields
  2. Ensure all values placed in the body map are JSON-serializable types (string, number, bool, nested maps/slices)
  3. 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

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


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/dc5650ce5e53f53e. Report an issue: GitHub.