chenhg5/cc-connect · error
dingtalk: marshal audio message: %w
Error message
dingtalk: marshal audio message: %w
What it means
SendAudio builds the oToMessages request body as a map and serializes it with json.Marshal; this error wraps a marshal failure. With the fixed string keys and primitive values used here (strings, an int duration), marshaling essentially cannot fail in normal operation — it is a defensive guard. Seeing it indicates corrupted data types or memory pressure.
Source
Thrown at platform/dingtalk/dingtalk.go:1265
// This is the official API for sending voice messages in bot conversations
token, err := p.getAccessToken()
if err != nil {
return fmt.Errorf("dingtalk: get access token: %w", err)
}
// Build oToMessages API request with sampleAudio msgKey
// msgParam must be a JSON string, not an object
msgParamJSON := fmt.Sprintf(`{"mediaId":"%s","duration":"%d"}`, mediaID, durationMs)
requestBody := map[string]interface{}{
"robotCode": p.robotCode,
"userIds": []string{rc.senderStaffId},
"msgKey": "sampleAudio",
"msgParam": msgParamJSON,
}
body, err := json.Marshal(requestBody)
if err != nil {
return fmt.Errorf("dingtalk: marshal audio message: %w", err)
}
slog.Debug("dingtalk: sending voice via oToMessages API", "media_id", mediaID, "duration", durationMs, "user_id", rc.senderStaffId)
req, err := http.NewRequestWithContext(ctx, http.MethodPost,
"https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend",
bytes.NewReader(body))
if err != nil {
return fmt.Errorf("dingtalk: create audio request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("x-acs-dingtalk-access-token", token)
resp, err := p.httpClient.Do(req)
if err != nil {
return fmt.Errorf("dingtalk: send audio request: %w", err)
}
defer func() { _ = resp.Body.Close() }()View on GitHub (pinned to 4000b2338a)
Solutions
- Inspect the wrapped error for the unmarshalable type
- Ensure all values in requestBody are JSON-encodable primitives
- Report a bug if it reproduces with unmodified code
Example fix
// before
requestBody := map[string]interface{}{"robotCode": code, "userIds": userIds, "msgKey": "sampleAudio", "msgParam": msgParamJSON}
// after — keep values as JSON-safe types; avoid channel/func/NaN values
requestBody := map[string]any{"robotCode": code, "userIds": []string{uid}, "msgKey": "sampleAudio", "msgParam": msgParamJSON} Defensive patterns
Strategy: try-catch
Validate before calling
// ensure all map values are JSON-encodable primitives
for k, v := range requestBody { if !isJSONSafe(v) { return fmt.Errorf("non-JSON-safe value at %s", k) } } Try / catch
if err := p.SendAudio(ctx, rc, audio, format); err != nil && strings.Contains(err.Error(), "marshal audio message") { log.Fatalf("non-JSON-encodable value in request body: %v", err) } Prevention
- Keep requestBody values limited to strings, ints, and slices of strings
- Use typed structs instead of map[string]interface{} to catch issues at compile time
- Treat this error as a code bug and file a report if it occurs
When it happens
Trigger: Calling SendAudio when json.Marshal fails on the requestBody map — practically only via abnormal values (e.g. someone placing an unmarshalable type like a channel or NaN in the map after code changes) or extreme memory conditions.
Common situations: Essentially never in production with stock code; appears after modifications to requestBody that add unsupported value types.
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 Agy permission hook: %w
- marshal Agy hooks overlay: %w
- marshal stdin: %w
- codex app-server encode: %w
- bridge: marshal reconstruct reply ctx: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/3783031c9c9c68f7.
Report an issue: GitHub.