{"record":{"id":"6911986439ce8c78","repo":"larksuite/cli","slug":"draft-main-body-is-text-html-and-text-plain-is-onl","errorCode":null,"errorMessage":"draft main body is text/html and text/plain is only its summary; set_body requires HTML input for this draft","messagePattern":"draft main body is text/html and text/plain is only its summary; set_body requires HTML input for this draft","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shortcuts/mail/draft/patch.go","lineNumber":407,"sourceCode":"\tif snapshot == nil {\n\t\treturn false\n\t}\n\ttextPart := findPart(snapshot.Body, snapshot.PrimaryTextPartID)\n\thtmlPart := findPart(snapshot.Body, snapshot.PrimaryHTMLPartID)\n\tif textPart == nil || htmlPart == nil {\n\t\treturn false\n\t}\n\treturn strings.EqualFold(textPart.MediaType, \"text/plain\") && strings.EqualFold(htmlPart.MediaType, \"text/html\")\n}\n\nfunc coupledBodySetBodyInputError(snapshot *DraftSnapshot, value string) error {\n\tif !hasCoupledBodySummary(snapshot) {\n\t\treturn nil\n\t}\n\tif bodyLooksLikeHTML(value) {\n\t\treturn nil\n\t}\n\treturn fmt.Errorf(\"draft main body is text/html and text/plain is only its summary; set_body requires HTML input for this draft\")\n}\n\nfunc bodyPartForKind(snapshot *DraftSnapshot, bodyKind string, allowRewrite bool) (*Part, error) {\n\tvar partID string\n\tswitch strings.ToLower(bodyKind) {\n\tcase \"text/plain\":\n\t\tpartID = snapshot.PrimaryTextPartID\n\tcase \"text/html\":\n\t\tpartID = snapshot.PrimaryHTMLPartID\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported body kind %q\", bodyKind)\n\t}\n\tif partID == \"\" {\n\t\tif !allowRewrite {\n\t\t\treturn nil, fmt.Errorf(\"draft has no primary %s body part\", bodyKind)\n\t\t}\n\t\treturn ensureBodyPart(snapshot, bodyKind)\n\t}","sourceCodeStart":389,"sourceCodeEnd":425,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/shortcuts/mail/draft/patch.go#L389-L425","documentation":"For drafts whose text/plain part is only a summary of the text/html body, set_body requires the new value to be HTML, because it writes the value into the HTML part and regenerates the plain-text summary. A non-HTML value would corrupt the coupled pair, so it is rejected up front.","triggerScenarios":"A set_body patch op on a coupled summary+html draft where bodyLooksLikeHTML(value) is false — i.e. the supplied value looks like plain text rather than HTML.","commonSituations":"Scripts that set plain-text bodies reused against HTML drafts; user input pasted as plain text; templates producing plain-text output applied to an HTML-format draft.","solutions":["Convert the value to HTML (wrap in <p>, escape entities) before calling set_body","Detect the coupled structure first and branch: HTML value for coupled drafts, plain text otherwise","Use replace_body with body_kind text/plain only if you intentionally want to break the coupling pattern (not recommended)"],"exampleFix":"// before\napplyOp(Op{Op: \"set_body\", Value: \"hello world\"}) // coupled draft requires HTML\n// after\napplyOp(Op{Op: \"set_body\", Value: \"<p>hello world</p>\"})","handlingStrategy":"validation","validationCode":"if draftHasCoupledSummary(snap) && !bodyLooksLikeHTML(value) {\n    value = \"<p>\" + html.EscapeString(value) + \"</p>\"\n}","typeGuard":"func isHTML(s string) bool { return strings.Contains(s, \"<p>\") || strings.Contains(s, \"<div>\") || strings.Contains(s, \"<br\") }","tryCatchPattern":"if err := applyOp(op); err != nil && strings.Contains(err.Error(), \"requires HTML input\") {\n    // wrap value in HTML and retry\n}","preventionTips":["Always produce HTML output when editing HTML drafts","Detect the coupled summary structure before set_body and branch on it","Escape plain text into HTML (html.EscapeString + <p> wrapper) as a default path"],"tags":["email","draft-patch","validation"],"backgroundTag":"body-format-mismatch","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"}