{"record":{"id":"2125c938faa395dd","repo":"chenhg5/cc-connect","slug":"dingtalk-marshal-proactive-message-w","errorCode":null,"errorMessage":"dingtalk: marshal proactive message: %w","messagePattern":"dingtalk: marshal proactive message: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/dingtalk/dingtalk.go","lineNumber":1680,"sourceCode":"\t\t\t\"msgParam\":           string(msgParam),\n\t\t}\n\t} else if rc.senderStaffId != \"\" {\n\t\t// Direct message via /v1.0/robot/oToMessages/batchSend\n\t\tapiURL = \"https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend\"\n\t\tmsgParam, _ := json.Marshal(map[string]string{\"title\": cardTitleFromContent(content), \"text\": content})\n\t\trequestBody = map[string]any{\n\t\t\t\"robotCode\": p.robotCode,\n\t\t\t\"userIds\":   []string{rc.senderStaffId},\n\t\t\t\"msgKey\":    \"sampleMarkdown\",\n\t\t\t\"msgParam\":  string(msgParam),\n\t\t}\n\t} else {\n\t\treturn fmt.Errorf(\"dingtalk: proactive send requires conversationId (group) or senderStaffId (direct)\")\n\t}\n\n\tbody, err := json.Marshal(requestBody)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"dingtalk: marshal proactive message: %w\", err)\n\t}\n\n\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, apiURL, bytes.NewReader(body))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"dingtalk: create proactive request: %w\", err)\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\treq.Header.Set(\"x-acs-dingtalk-access-token\", token)\n\n\tresp, err := p.httpClient.Do(req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"dingtalk: proactive send request: %w\", err)\n\t}\n\tdefer func() { _ = resp.Body.Close() }()\n\n\trespBody, _ := io.ReadAll(resp.Body)\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"dingtalk: proactive send failed: status=%d, body=%s\", resp.StatusCode, string(respBody))","sourceCodeStart":1662,"sourceCodeEnd":1698,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/dingtalk/dingtalk.go#L1662-L1698","documentation":"This error wraps a json.Marshal failure while serializing the proactive message payload (robotCode, userIds/conversationId, msgKey, msgParam) into the HTTP request body. It indicates the request struct could not be converted to JSON, which for these plain types almost always means an unexpected value ended up in the payload (e.g. an unsupported type slipped into msgParam or a nested field).","triggerScenarios":"json.Marshal(requestBody) returns an error immediately after building the proactive-send request map in the proactive send function.","commonSituations":"Embedding a non-JSON-serializable value (channel, func, cyclic structure) into the request body via custom options; corrupted msgParam bytes assembly upstream.","solutions":["Inspect the wrapped error (%w) to see the exact Go type that failed to marshal.","Ensure msgParam is produced via json.Marshal of a plain map/struct (string), not raw dynamic values.","Log the requestBody structure (with token redaction) in a debug build to find the offending field.","If the marshal error persists with plain types, report it as a bug — stdlib json.Marshal cannot fail on map[string]any of strings/slices."],"exampleFix":"// before\nmsgParam, _ := somethingDynamic() // may be non-serializable\nrequestBody[\"msgParam\"] = msgParam\n// after\nmsgParamBytes, err := json.Marshal(map[string]string{\"content\": content})\nif err != nil {\n    return fmt.Errorf(\"dingtalk: build msgParam: %w\", err)\n}\nrequestBody[\"msgParam\"] = string(msgParamBytes)","handlingStrategy":"try-catch","validationCode":"if _, err := json.Marshal(requestBody); err != nil {\n    slog.Error(\"payload not serializable\", \"err\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := p.Send(ctx, rc, msg); err != nil {\n    if strings.Contains(err.Error(), \"marshal proactive message\") {\n        slog.Error(\"proactive payload invalid\", \"err\", err)\n    }\n}","preventionTips":["Keep the request body to JSON-safe types (string, map, slice)","Always build msgParam via json.Marshal of a plain map","Never insert dynamic values like channels or funcs into the request map"],"tags":["dingtalk","json","serialization","proactive-send"],"backgroundTag":"json-marshal-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}