larksuite/cli · error

draft main body is text/html and text/plain is only its summ

Error message

draft main body is text/html and text/plain is only its summary; set_body requires HTML input for this draft

What it means

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.

Source

Thrown at shortcuts/mail/draft/patch.go:407

	if snapshot == nil {
		return false
	}
	textPart := findPart(snapshot.Body, snapshot.PrimaryTextPartID)
	htmlPart := findPart(snapshot.Body, snapshot.PrimaryHTMLPartID)
	if textPart == nil || htmlPart == nil {
		return false
	}
	return strings.EqualFold(textPart.MediaType, "text/plain") && strings.EqualFold(htmlPart.MediaType, "text/html")
}

func coupledBodySetBodyInputError(snapshot *DraftSnapshot, value string) error {
	if !hasCoupledBodySummary(snapshot) {
		return nil
	}
	if bodyLooksLikeHTML(value) {
		return nil
	}
	return fmt.Errorf("draft main body is text/html and text/plain is only its summary; set_body requires HTML input for this draft")
}

func bodyPartForKind(snapshot *DraftSnapshot, bodyKind string, allowRewrite bool) (*Part, error) {
	var partID string
	switch strings.ToLower(bodyKind) {
	case "text/plain":
		partID = snapshot.PrimaryTextPartID
	case "text/html":
		partID = snapshot.PrimaryHTMLPartID
	default:
		return nil, fmt.Errorf("unsupported body kind %q", bodyKind)
	}
	if partID == "" {
		if !allowRewrite {
			return nil, fmt.Errorf("draft has no primary %s body part", bodyKind)
		}
		return ensureBodyPart(snapshot, bodyKind)
	}

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Convert the value to HTML (wrap in <p>, escape entities) before calling set_body
  2. Detect the coupled structure first and branch: HTML value for coupled drafts, plain text otherwise
  3. Use replace_body with body_kind text/plain only if you intentionally want to break the coupling pattern (not recommended)

Example fix

// before
applyOp(Op{Op: "set_body", Value: "hello world"}) // coupled draft requires HTML
// after
applyOp(Op{Op: "set_body", Value: "<p>hello world</p>"})
Defensive patterns

Strategy: validation

Validate before calling

if draftHasCoupledSummary(snap) && !bodyLooksLikeHTML(value) {
    value = "<p>" + html.EscapeString(value) + "</p>"
}

Type guard

func isHTML(s string) bool { return strings.Contains(s, "<p>") || strings.Contains(s, "<div>") || strings.Contains(s, "<br") }

Try / catch

if err := applyOp(op); err != nil && strings.Contains(err.Error(), "requires HTML input") {
    // wrap value in HTML and retry
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/6911986439ce8c78. Report an issue: GitHub.