{"record":{"id":"01ba6a82d4e23850","repo":"larksuite/cli","slug":"draft-has-both-text-plain-and-text-html-body-parts","errorCode":null,"errorMessage":"draft has both text/plain and text/html body parts, but they are not a supported summary+html pair","messagePattern":"draft has both text/plain and text/html body parts, but they are not a supported summary\\+html pair","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shortcuts/mail/draft/patch.go","lineNumber":299,"sourceCode":"//\n// This mirrors how normal attachments (independent MIME parts) survive\n// body edits — giving consistent mental model: attachments and signature\n// are draft-level concerns, not body content.\nfunc setBody(snapshot *DraftSnapshot, value string, options PatchOptions) error {\n\tvalue = autoPreserveSystemManagedRegions(snapshot, value)\n\tswitch {\n\tcase snapshot.PrimaryTextPartID != \"\" && snapshot.PrimaryHTMLPartID == \"\":\n\t\treturn replaceBody(snapshot, \"text/plain\", value, options)\n\tcase snapshot.PrimaryTextPartID == \"\" && snapshot.PrimaryHTMLPartID != \"\":\n\t\treturn replaceBody(snapshot, \"text/html\", value, options)\n\tcase snapshot.PrimaryTextPartID != \"\" && snapshot.PrimaryHTMLPartID != \"\":\n\t\tif err := coupledBodySetBodyInputError(snapshot, value); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif tryApplyCoupledBodySetBody(snapshot, value) {\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(\"draft has both text/plain and text/html body parts, but they are not a supported summary+html pair\")\n\tdefault:\n\t\treturn fmt.Errorf(\"draft has no unique primary body part; use replace_body with body_kind\")\n\t}\n}\n\n// autoPreserveSystemManagedRegions extracts system-managed elements\n// (signature block and large attachment card) from the draft's old HTML\n// body and injects them into value (before any quote block in value, or\n// appended when no quote). Order is [sig][card], matching compose-time\n// layout [user][sig][card][quote].\n//\n// For each element, auto-injection is skipped when value's\n// user-authored region (before any quote block in value) already\n// contains that element — so users who explicitly reconstruct the body\n// with their own signature / card are respected. Elements inside a\n// quote block in value belong to the quoted original message and are\n// ignored for this check.\n//","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/shortcuts/mail/draft/patch.go#L281-L317","documentation":"When a draft has both a text/plain and a text/html primary part, set_body can only replace them together if they form a recognized summary+html pair. If the two parts are not such a supported pair (and the input was valid for the coupled path), set_body gives up rather than guessing which part the value should replace.","triggerScenarios":"A set_body patch op on a snapshot with both PrimaryTextPartID and PrimaryHTMLPartID set, where the parts are NOT a coupled summary pair (so coupledBodySetBodyInputError passes) and tryApplyCoupledBodySetBody fails to apply the value to both parts.","commonSituations":"Multipart/alternative drafts authored externally with genuinely different text and HTML content (not a summary); forwarded or quoted drafts with two independent body parts.","solutions":["Use replace_body with an explicit body_kind (text/plain or text/html) to target one part","Inspect the draft's MIME structure to confirm which parts exist and their relationship","Remove or rebuild one of the body parts so the draft has a unique primary body"],"exampleFix":"// before\napplyOp(Op{Op: \"set_body\", Value: text}) // draft has unrelated text+html parts\n// after\napplyOp(Op{Op: \"replace_body\", BodyKind: \"text/html\", Value: html})","handlingStrategy":"validation","validationCode":"if snap.PrimaryTextPartID != \"\" && snap.PrimaryHTMLPartID != \"\" && !isCoupledSummaryPair(snap) {\n    // use replace_body with explicit body_kind\n}","typeGuard":null,"tryCatchPattern":"if err := applyOp(op); err != nil && strings.Contains(err.Error(), \"not a supported summary+html pair\") {\n    // retry with Op{Op: \"replace_body\", BodyKind: \"text/html\", ...}\n}","preventionTips":["Inspect the MIME structure of externally created drafts before set_body","Use replace_body with an explicit body_kind for non-standard multipart bodies","Normalize drafts to a supported single-body or summary+html shape when possible"],"tags":["email","draft-patch","mime"],"backgroundTag":"unsupported-multipart-structure","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}