{"record":{"id":"2b4c8a2ef7fba970","repo":"chenhg5/cc-connect","slug":"s-upload-audio-no-file-key-returned","errorCode":null,"errorMessage":"%s: upload audio: no file_key returned","messagePattern":"(.+?): upload audio: no file_key returned","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/feishu/feishu.go","lineNumber":5503,"sourceCode":"\t\t\t\t\tFileName(\"tts_audio.opus\").\n\t\t\t\t\tFile(bytes.NewReader(audio)).\n\t\t\t\t\tBuild()).\n\t\t\t\tBuild()\n\t\t\tvar err error\n\t\t\tuploadResp, err = client.Im.File.Create(ctx, req, options...)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"%s: upload audio: %w\", p.tag(), err)\n\t\t\t}\n\t\t\tif !uploadResp.Success() {\n\t\t\t\treturn fmt.Errorf(\"%s: upload audio code=%d msg=%s\", p.tag(), uploadResp.Code, uploadResp.Msg)\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n\t}); err != nil {\n\t\treturn err\n\t}\n\tif uploadResp.Data == nil || uploadResp.Data.FileKey == nil {\n\t\treturn fmt.Errorf(\"%s: upload audio: no file_key returned\", p.tag())\n\t}\n\tfileKey := *uploadResp.Data.FileKey\n\n\tslog.Debug(p.tag()+\": audio uploaded\", \"file_key\", fileKey, \"format\", format, \"size\", len(audio))\n\n\taudioMsg := larkim.MessageAudio{FileKey: fileKey}\n\taudioContent, err := audioMsg.String()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"%s: build audio message: %w\", p.tag(), err)\n\t}\n\n\t// Diagnostic for QA-reported intermittent \"audio rendered as file\" in\n\t// P2P reply mode (see internal task t-20260615-cqjbk1). Tracking the\n\t// API path lets operators correlate Feishu client renders to whether\n\t// we used Reply (in-thread) or Create (new message) when issues\n\t// recur. The Reply path has historically had narrower MsgType\n\t// support on some Feishu desktop client versions.\n\tif p.shouldUseThreadOrReplyAPI(rc) {","sourceCodeStart":5485,"sourceCodeEnd":5521,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/feishu/feishu.go#L5485-L5521","documentation":"After a supposedly successful upload, SendAudio validates that the response contains a file_key (uploadResp.Data.FileKey). If the response body has no Data or no FileKey pointer, this error is thrown because a voice message cannot be built without the key. It indicates an unexpected API response shape — the SDK reported Success but returned an empty payload.","triggerScenarios":"Feishu's Im.File.Create returns a 200/Success envelope with an empty or malformed body: partial outage, API contract change in the SDK/lark version, or a proxy that strips/degrades the response body.","commonSituations":"Upgrading the larksuite/lark SDK to a version with a changed response schema; corporate proxy mangling JSON responses; Feishu incident causing truncated bodies.","solutions":["Pin/verify the github.com/larksuite/oapi-sdk version matches what this platform expects (go.mod / go.sum)","Log the full uploadResp JSON when this occurs and compare against Feishu docs","Retry — if intermittent, it may be a transient Feishu-side anomaly","Check for proxies/middleboxes altering response bodies"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// after any Feishu upload, before using the result\nif uploadResp == nil || uploadResp.Data == nil || uploadResp.Data.FileKey == nil || *uploadResp.Data.FileKey == \"\" {\n    return errors.New(\"feishu: upload returned no file_key\")\n}","typeGuard":"func validFileKey(r *larkim.CreateFileResp) bool { return r != nil && r.Data != nil && r.Data.FileKey != nil && *r.Data.FileKey != \"\" }","tryCatchPattern":"if err := p.SendAudio(ctx, rc, audio, \"opus\"); err != nil && strings.Contains(err.Error(), \"no file_key\") {\n    // retry once; if persistent, pin SDK version / check proxy\n}","preventionTips":["Pin the lark SDK version in go.mod","Log raw response JSON on anomalies","Bypass response-altering proxies","Monitor Feishu status for incidents"],"tags":["feishu","upload","unexpected-response","audio"],"backgroundTag":"unexpected-api-response-shape","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"}