{"record":{"id":"f4a559a76abc7fb7","repo":"chenhg5/cc-connect","slug":"discord-send-file-fallback-w","errorCode":null,"errorMessage":"discord: send file fallback: %w","messagePattern":"discord: send file fallback: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/discord/discord.go","lineNumber":1133,"sourceCode":"\t\trc.mu.Unlock()\n\n\t\tvar err error\n\t\tif first {\n\t\t\t_, err = p.session.InteractionResponseEdit(rc.interaction, &discordgo.WebhookEdit{\n\t\t\t\tFiles: []*discordgo.File{newFile()},\n\t\t\t})\n\t\t} else {\n\t\t\t_, err = p.session.FollowupMessageCreate(rc.interaction, true, &discordgo.WebhookParams{\n\t\t\t\tFiles: []*discordgo.File{newFile()},\n\t\t\t})\n\t\t}\n\t\tif err != nil {\n\t\t\tslog.Warn(\"discord: interaction file failed, falling back to channel message\", \"error\", err)\n\t\t\t_, err = p.session.ChannelMessageSendComplex(rc.channelID, &discordgo.MessageSend{\n\t\t\t\tFiles: []*discordgo.File{newFile()},\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"discord: send file fallback: %w\", err)\n\t\t\t}\n\t\t}\n\t\treturn nil\n\tcase replyContext:\n\t\t_, err := p.session.ChannelMessageSendComplex(rc.targetChannelID(), &discordgo.MessageSend{\n\t\t\tFiles: []*discordgo.File{newFile()},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"discord: send file: %w\", err)\n\t\t}\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"discord: SendFile: invalid reply context type %T\", rctx)\n\t}\n}\n\nfunc buildDiscordActionRows(rows [][]core.ButtonOption) []discordgo.MessageComponent {\n\tcomponents := make([]discordgo.MessageComponent, 0, len(rows))","sourceCodeStart":1115,"sourceCodeEnd":1151,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/discord/discord.go#L1115-L1151","documentation":"SendFile failed to deliver a file attachment through the Discord interaction webhook AND the fallback ChannelMessageSendComplex upload in the originating channel also failed. Both delivery paths returned errors from the Discord API (or transport), so the attachment was never delivered. The wrapped error is from the fallback multipart upload.","triggerScenarios":"Interaction expired/invalid plus fallback failure: 403 Missing Permissions or Missing Attach Files, deleted channel, file exceeding the guild upload size limit, or network/proxy failure during upload.","commonSituations":"Sending large generated files (build artifacts, diffs) over Discord's upload cap; bot permissions revoked mid-conversation; session outliving the interaction's 15-minute window while the channel also became inaccessible.","solutions":["Inspect the wrapped error code: 403 → grant Send Messages + Attach Files to the bot role in that channel; size errors → reduce file size or compress","Verify the channel (rc.channelID) still exists and the bot is still in the guild","Check file.MimeType and FileName are valid and match the payload","If files are consistently too large, host externally and send a link instead of an attachment"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"const maxUpload = 8 << 20\nif len(file.Data) > maxUpload {\n    return fmt.Errorf(\"file %s (%d bytes) exceeds discord upload limit\", file.FileName, len(file.Data))\n}","typeGuard":null,"tryCatchPattern":"var apiErr *discordgo.RESTError\nif errors.As(err, &apiErr) {\n    switch apiErr.Message.Code {\n    case 50013: // missing permissions\n        slog.Error(\"discord: bot cannot attach files in channel\", \"channel\", rc.channelID)\n    case 40005: // request entity too large\n        slog.Error(\"discord: file too large for upload\", \"file\", file.FileName)\n    }\n}","preventionTips":["Check file size against the guild upload limit before sending","Grant Attach Files permission to the bot role","Use external hosting + links for large files instead of attachments","Send files within the interaction window or accept plain channel delivery only"],"tags":["discord","api-error","permissions","file-upload"],"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"}