larksuite/cli · error

draft has no primary %s body part

Error message

draft has no primary %s body part

What it means

This error means the draft's MIME snapshot has no primary body part of the requested kind (text/plain or text/html): PrimaryTextPartID or PrimaryHTMLPartID is empty. bodyPartForKind only auto-creates a missing body when allowRewrite is true (e.g. rewrite_entire_draft); plain replaceBody/appendBody operations require an existing primary part and refuse to synthesize one. It protects drafts whose structure doesn't include that body variant from being silently restructured by a targeted body patch.

Source

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

	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)
	}
	part := findPart(snapshot.Body, partID)
	if part == nil {
		return nil, fmt.Errorf("body part %s not found", partID)
	}
	return part, nil
}

func ensureBodyPart(snapshot *DraftSnapshot, bodyKind string) (*Part, error) {
	partRef := primaryBodyRootRef(&snapshot.Body)
	if partRef == nil {
		return nil, fmt.Errorf("draft has no primary body container")
	}
	return ensureBodyPartRef(partRef, bodyKind)
}

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Check which body kind the draft actually has before patching (inspect the draft's MIME structure / primary part IDs) and request the matching kind.
  2. Use the rewrite_entire_draft path (allowRewrite=true) instead of set_body/append_body when the missing body kind should be synthesized.
  3. Convert the draft's body to the desired structure first (e.g. set the body once via rewrite) so the primary part exists, then apply targeted patches.

Example fix

// before: patching text/plain on an HTML-only draft
err := replaceBody(ctx, snapshot, "text/plain", body)
// after: rewrite so the missing primary part is created
err := replaceBodyAllowRewrite(ctx, snapshot, "text/plain", body) // allowRewrite=true
Defensive patterns

Strategy: validation

Validate before calling

func canPatchBody(s *DraftSnapshot, kind string) bool {
	id := s.PrimaryTextPartID
	if kind == "text/html" {
		id = s.PrimaryHTMLPartID
	}
	return id != "" && findPart(s.Body, id) != nil
}
if !canPatchBody(snapshot, "text/plain") { /* use rewrite path */ }

Type guard

func hasPrimaryBody(s *DraftSnapshot, kind string) bool {
	id := s.PrimaryTextPartID
	if strings.EqualFold(kind, "text/html") { id = s.PrimaryHTMLPartID }
	return id != "" && findPart(s.Body, id) != nil
}

Prevention

When it happens

Trigger: Calling replaceBody or appendBody (via draft patch body operations like set_body/append_body) on a draft whose snapshot lacks a primary part for the requested bodyKind — e.g. patching text/plain on an HTML-only draft, or patching text/html on a plain-text-only draft.

Common situations: Patching a draft created with only one body representation; drafts fetched from the API where one MIME leaf is absent; automation scripts that assume every draft has both text and HTML bodies; using set_body on an attachment-only or unusual MIME structure.

Related errors


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