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
- Check which body kind the draft actually has before patching (inspect the draft's MIME structure / primary part IDs) and request the matching kind.
- Use the rewrite_entire_draft path (allowRewrite=true) instead of set_body/append_body when the missing body kind should be synthesized.
- 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
- Inspect the draft's MIME structure before choosing which body kind to patch.
- Prefer the rewrite (allowRewrite) path when the draft may lack one body representation.
- Never assume both text/plain and text/html exist; single-representation drafts are common.
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
- body part %s not found
- draft has no primary body container
- body container is nil
- cannot rewrite non-body media type %q
- rewrite_entire_draft cannot synthesize body inside %q
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/4088294d3c8ea595.
Report an issue: GitHub.