{"record":{"id":"fe8e03728f1cf1ca","repo":"chenhg5/cc-connect","slug":"s-upload-audio-w","errorCode":null,"errorMessage":"%s: upload audio: %w","messagePattern":"(.+?): upload audio: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/feishu/feishu.go","lineNumber":5492,"sourceCode":"\t\t}\n\t\taudio = converted\n\t\tformat = \"opus\"\n\t}\n\n\tvar uploadResp *larkim.CreateFileResp\n\tif err := p.withTransientRetry(ctx, \"upload audio\", func() error {\n\t\treturn p.withFreshTenantAccessTokenRetry(ctx, \"upload audio\", func(client *lark.Client, options ...larkcore.RequestOptionFunc) error {\n\t\t\treq := larkim.NewCreateFileReqBuilder().\n\t\t\t\tBody(larkim.NewCreateFileReqBodyBuilder().\n\t\t\t\t\tFileType(larkim.FileTypeOpus).\n\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()","sourceCodeStart":5474,"sourceCodeEnd":5510,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/feishu/feishu.go#L5474-L5510","documentation":"This wraps an SDK-level failure from client.Im.File.Create, the Feishu upload API used to push the audio file before it can be referenced by a voice message. The upload runs inside withFreshTenantAccessTokenRetry (inside transient retry), so seeing this error means the upload failed even after retries with a freshly issued tenant_access_token.","triggerScenarios":"client.Im.File.Create returns a non-nil err after retries: network failure, token acquisition failure, ctx cancellation mid-upload (large files on slow links), or multipart request build failure.","commonSituations":"Large audio files timing out on constrained networks; Feishu open platform outage; app credentials revoked so fresh token fetch fails inside the retry wrapper; proxy blocking multipart uploads.","solutions":["Inspect the unwrapped cause to distinguish network vs auth vs cancellation","Verify tenant_access_token acquisition works (check app_id/app_secret)","Retry later — transient-retry already ran, so the failure is likely persistent","Reduce audio size/duration to shrink the upload"],"exampleFix":"err := p.SendAudio(ctx, rc, audio, \"opus\")\nif err != nil {\n    slog.Error(\"feishu audio upload failed after retries\", \"err\", err)\n    // fall back to sending a text notice instead\n    p.Reply(ctx, rc, \"(voice message failed to upload)\")\n}","handlingStrategy":"retry","validationCode":"// pre-check token acquisition\n// ensure ctx has sufficient deadline for large uploads\nif d, ok := ctx.Deadline(); ok && time.Until(d) < 30*time.Second { /* extend deadline */ }","typeGuard":null,"tryCatchPattern":"err := p.SendAudio(ctx, rc, audio, \"opus\")\nif err != nil {\n    if errors.Is(err, context.Canceled) { return err } // don't retry cancellations\n    time.Sleep(backoff); err = p.SendAudio(ctx, rc, audio, \"opus\")\n}","preventionTips":["Size audio within Feishu upload limits","Ensure stable connectivity to open.feishu.cn","Keep app_id/app_secret valid so fresh-token retries succeed","Bound retry attempts with exponential backoff"],"tags":["feishu","upload","network","audio"],"backgroundTag":"api-request-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}