{"record":{"id":"ae1d4ed8a27797ba","repo":"chenhg5/cc-connect","slug":"dingtalk-emotion-returned-status-d-s","errorCode":null,"errorMessage":"dingtalk: emotion returned status %d: %s","messagePattern":"dingtalk: emotion returned status (.+?): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/dingtalk/dingtalk.go","lineNumber":967,"sourceCode":"\t\treturn fmt.Errorf(\"dingtalk: marshal emotion request: %w\", err)\n\t}\n\n\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, \"https://api.dingtalk.com\"+path, bytes.NewReader(body))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"dingtalk: create emotion 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: emotion 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: emotion returned status %d: %s\", resp.StatusCode, string(respBody))\n\t}\n\tif len(respBody) == 0 {\n\t\treturn nil\n\t}\n\tvar result struct {\n\t\tSuccess *bool `json:\"success\"`\n\t}\n\tif err := json.Unmarshal(respBody, &result); err == nil && result.Success != nil && !*result.Success {\n\t\treturn fmt.Errorf(\"dingtalk: emotion returned success=false\")\n\t}\n\treturn nil\n}\n\n// StartTyping adds a DingTalk emotion to the user's message while the agent is processing.\nfunc (p *Platform) StartTyping(ctx context.Context, rctx any) (stop func()) {\n\trc, ok := rctx.(replyContext)\n\tif !ok || p.reactionEmoji == \"\" || rc.messageID == \"\" || rc.conversationId == \"\" {\n\t\treturn func() {}","sourceCodeStart":949,"sourceCodeEnd":985,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/dingtalk/dingtalk.go#L949-L985","documentation":"This error is returned by sendEmotion when DingTalk's emotion API responds with a non-200 HTTP status code. The message includes the status code and the raw response body, which contains DingTalk's machine-readable error code and message (e.g. invalid authentication, forbidden robot, throttled request). It means the request reached DingTalk and was rejected at the HTTP layer — unlike err 1063, this is an application-level refusal, not a transport failure.","triggerScenarios":"p.httpClient.Do succeeds but resp.StatusCode != 200 for /v1.0/robot/emotion/reply or /robot/emotion/recall — expired/invalid access token (401/400), robot not permitted for emotion replies, invalid backgroundID/emoji payload, or DingTalk server errors (5xx).","commonSituations":"Access token expired between fetch and use; app lacks the Robot emotion API permission scope in the DingTalk console; calling reply on a message the robot is not allowed to react to; DingTalk-side 5xx during an incident.","solutions":["Read the response body in the error message — it contains DingTalk's errcode/errmsg pinpointing the cause","If 401/token errors: verify appKey/appSecret and re-fetch (token may have just expired)","If permission errors: enable the required robot/emotion API permissions for the app in the DingTalk developer console","If 429 or 5xx: back off and retry; check DingTalk status for incidents","Confirm the emoji/backgroundID payload matches DingTalk's documented values"],"exampleFix":"// before: reacting with an app lacking emotion permission -> status 403\n// after: enable \"企业机器人-表情回复\" (robot emotion) API permission\n// in DingTalk open platform console under the app's Permission Management, then redeploy","handlingStrategy":"try-catch","validationCode":"// Go: pre-flight token check to avoid 401-class rejections\ntok, err := p.getAccessToken()\nif err != nil || tok == \"\" {\n    return fmt.Errorf(\"dingtalk: no valid token before emotion send: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := p.AddDoneReaction(ctx, msg); err != nil {\n    var httpErr interface{ Error() string }\n    if strings.Contains(err.Error(), \"emotion returned status\") {\n        // parse embedded status/body for DingTalk errcode\n        slog.Warn(\"dingtalk emotion rejected\", \"detail\", err)\n    }\n    _ = httpErr\n}","preventionTips":["Grant the robot app all emotion-reply API scopes in the DingTalk console before enabling features","Handle 401/403 by refreshing credentials rather than blind retries","Log the response body embedded in the error — it carries DingTalk's errcode/errmsg","Watch DingTalk status pages for 5xx incidents"],"tags":["dingtalk","http","api","error-response"],"backgroundTag":"http-error-response","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"}