chenhg5/cc-connect · warning
qqbot: marshal body: %w
Error message
qqbot: marshal body: %w
What it means
apiRequestJSON serializes the request body to JSON before issuing the HTTP call; a json.Marshal failure is wrapped with this message. In practice this is rare because bodies are maps/slices of JSON-safe values, but non-serializable types (channels, funcs, NaN floats, cycles) trigger it before any network I/O happens.
Source
Thrown at platform/qqbot/qqbot.go:309
var result struct {
FileInfo string `json:"file_info"`
}
if err := p.apiRequestJSON("POST", url, reqBody, &result); err != nil {
return "", err
}
if result.FileInfo == "" {
return "", fmt.Errorf("qqbot: upload rich media: empty file_info")
}
return result.FileInfo, nil
}
// apiRequestJSON is like apiRequest but also decodes the response body into result.
func (p *Platform) apiRequestJSON(method, url string, body any, result any) error {
var bodyReader io.Reader
if body != nil {
data, err := json.Marshal(body)
if err != nil {
return fmt.Errorf("qqbot: marshal body: %w", err)
}
bodyReader = bytes.NewReader(data)
}
token, err := p.getAccessToken()
if err != nil {
return fmt.Errorf("qqbot: get token: %w", err)
}
req, err := http.NewRequest(method, url, bodyReader)
if err != nil {
return err
}
req.Header.Set("Authorization", "QQBot "+token)
req.Header.Set("Content-Type", "application/json")
resp, err := core.HTTPClient.Do(req)
if err != nil {View on GitHub (pinned to 4000b2338a)
Solutions
- Inspect the wrapped inner error (%w): json.UnsupportedTypeError names the offending type, UnsupportedValueError names the value.
- Remove or convert non-serializable values (func/channel/mutex) from the request body.
- Replace NaN/Inf floats with strings or omit them.
- If a custom body is being injected, pre-validate it with json.Marshal in a test.
- Keep bodies restricted to the adapter's internally built map[string]any payloads.
Example fix
// before
body := map[string]any{"file_type": 4, "callback": func() {}} // func not JSON-encodable
err := p.apiRequestJSON("POST", url, body, &result) // marshal body error
// after
body := map[string]any{"file_type": 4, "file_data": b64, "srv_send_msg": false}
err := p.apiRequestJSON("POST", url, body, &result) Defensive patterns
Strategy: try-catch
Validate before calling
if _, err := json.Marshal(body); err != nil {
return fmt.Errorf("request body not JSON-encodable: %w", err)
} Try / catch
if err := p.apiRequestJSON("POST", url, body, &result); err != nil {
var uErr *json.UnsupportedTypeError
var vErr *json.UnsupportedValueError
if errors.As(err, &uErr) || errors.As(err, &vErr) {
// bad value in body map; drop/convert it, no retry will help
}
} Prevention
- Keep request bodies to JSON-safe primitives, slices, and maps only.
- Never insert funcs, channels, or mutexes into option/body maps.
- Sanitize float values (NaN/Inf) before adding them to a body.
- Add a unit test that marshals every body the adapter builds.
When it happens
Trigger: Passing a body map[string]any containing a value that cannot be marshaled — e.g. a func, channel, sync.Mutex stored in an option, cyclic structure, or math.NaN()/Inf() float.
Common situations: Callers injecting extra fields into request bodies with non-JSON-safe values; debugging code that stuffs a request context object into the body; copy-pasted code passing structs with unexported-only or unsupported fields.
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
- codex app-server encode: %w
- marshal: %w
- piSession: marshal command: %w
- piSession: marshal extension_ui_response: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/e66330a5d93ef643.
Report an issue: GitHub.