{"record":{"id":"cffe684a468a3dee","repo":"chenhg5/cc-connect","slug":"discord-invalid-preview-handle-type-t","errorCode":null,"errorMessage":"discord: invalid preview handle type %T","messagePattern":"discord: invalid preview handle type %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/discord/discord.go","lineNumber":1279,"sourceCode":"\tcase *interactionReplyCtx:\n\t\tchannelID = rc.channelID\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"discord: invalid reply context type %T\", rctx)\n\t}\n\n\tmsg := buildDiscordPreviewMessage(content)\n\tsent, err := p.session.ChannelMessageSendComplex(channelID, msg)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"discord: send preview: %w\", err)\n\t}\n\treturn &discordPreviewHandle{channelID: channelID, messageID: sent.ID}, nil\n}\n\n// UpdateMessage edits an existing message identified by previewHandle.\nfunc (p *Platform) UpdateMessage(ctx context.Context, previewHandle any, content string) error {\n\th, ok := previewHandle.(*discordPreviewHandle)\n\tif !ok {\n\t\treturn fmt.Errorf(\"discord: invalid preview handle type %T\", previewHandle)\n\t}\n\t_, err := p.session.ChannelMessageEditComplex(buildDiscordPreviewEdit(h.channelID, h.messageID, content))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"discord: edit message: %w\", err)\n\t}\n\treturn nil\n}\n\n// DeletePreviewMessage removes the preview message so the final response can\n// be sent as a fresh message (avoids notification confusion).\nfunc (p *Platform) DeletePreviewMessage(ctx context.Context, previewHandle any) error {\n\th, ok := previewHandle.(*discordPreviewHandle)\n\tif !ok {\n\t\treturn fmt.Errorf(\"discord: invalid preview handle type %T\", previewHandle)\n\t}\n\treturn p.session.ChannelMessageDelete(h.channelID, h.messageID)\n}\n","sourceCodeStart":1261,"sourceCodeEnd":1297,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/discord/discord.go#L1261-L1297","documentation":"UpdateMessage requires the previewHandle argument to be the *discordPreviewHandle previously returned by SendPreviewStart; any other value fails this check before editing. This guards against editing with a handle from another platform or a stale/incorrect value. The %T output identifies the actual type received.","triggerScenarios":"UpdateMessage called with a handle obtained from a different platform's preview implementation, a raw message-ID string, or nil instead of the handle returned by SendPreviewStart.","commonSituations":"Mixing preview implementations across platform adapters; persisting handles in a lossy format (e.g. JSON without type) and re-decoding into the wrong type; ignoring SendPreviewStart's return value.","solutions":["Always thread through the exact *discordPreviewHandle returned by SendPreviewStart","Check the %T in the error to find which code path produced the wrong handle type","Recreate the preview via SendPreviewStart if the handle was lost; handles are not reconstructible from IDs alone in this API","Type-assert at the call site and handle failure gracefully before calling UpdateMessage"],"exampleFix":"// before\np.UpdateMessage(ctx, messageIDString, content)\n// after\nhandle, err := p.SendPreviewStart(ctx, rctx, content)\nif err != nil { return err }\nreturn p.UpdateMessage(ctx, handle, content)","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isValidPreviewHandle(h any) bool {\n    _, ok := h.(*discordPreviewHandle)\n    return ok\n}","tryCatchPattern":"if err := p.UpdateMessage(ctx, previewHandle, content); err != nil {\n    if strings.Contains(err.Error(), \"invalid preview handle type\") {\n        log.Printf(\"bad handle %T; recreating preview\", previewHandle)\n        return recreatePreview(ctx, content)\n    }\n    return err\n}","preventionTips":["Keep the exact handle returned by SendPreviewStart (same in-memory type)","Never persist/decode handles into foreign types; store channelID/messageID fields and rebuild via the platform","Do not share preview handles across platform adapters","Ignore-not: always check SendPreviewStart's error and handle rather than dropping them"],"tags":["discord","type-mismatch","preview","handle","programming-error"],"backgroundTag":"incompatible-source-type","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"}