larksuite/cli · error
body part %s not found
Error message
body part %s not found
What it means
The snapshot records a primary part ID for the requested body kind, but findPart cannot locate that part anywhere in the draft's MIME tree. This means the snapshot's part registry (PrimaryTextPartID/PrimaryHTMLPartID) is out of sync with the actual Part tree — a stale or internally inconsistent snapshot. The library refuses to patch a dangling reference rather than patching the wrong node.
Source
Thrown at shortcuts/mail/draft/patch.go:428
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)
}
func primaryBodyRootRef(root **Part) **Part {
if root == nil || *root == nil {
return root
}
part := *root
if strings.EqualFold(part.MediaType, "multipart/mixed") {View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Re-fetch/re-parse the draft to obtain a fresh, consistent DraftSnapshot before patching.
- Fix the mutation code so any tree restructuring updates PrimaryTextPartID/PrimaryHTMLPartID (or leaves them intact).
- Clear the stale primary ID (set it to "") so the draft goes through the ensureBodyPart path with allowRewrite instead of dangling.
Example fix
// before: stale snapshot reused after body restructure part, err := bodyPartForKind(staleSnapshot, "text/html", false) // after: rebuild snapshot from current draft snapshot, err := parseDraftSnapshot(currentDraft) part, err := bodyPartForKind(snapshot, "text/html", false)
Defensive patterns
Strategy: validation
Validate before calling
if snapshot.PrimaryHTMLPartID != "" && findPart(snapshot.Body, snapshot.PrimaryHTMLPartID) == nil {
// stale reference: re-fetch the draft and rebuild the snapshot
snapshot = reparseDraft(latestDraft)
} Type guard
func primaryPartResolvable(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
- Never reuse a DraftSnapshot after the draft body was restructured externally.
- Always update primary part IDs when mutating the MIME tree.
- Re-parse the draft from its current state before each patch round.
When it happens
Trigger: Calling replaceBody or appendBody with a snapshot where PrimaryTextPartID or PrimaryHTMLPartID points to a part ID absent from snapshot.Body — e.g. after external mutation of the tree, a partially-failed earlier patch, or a snapshot built from a MIME message where the referenced leaf was dropped.
Common situations: Reusing a DraftSnapshot parsed from an older version of the draft after the body was restructured; custom code that removed/replaced parts without updating primary IDs; bugs in downstream MIME rebuilds that orphan the primary leaf.
Related errors
- draft has no primary %s body part
- 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/7fe3e6b72aecf819.
Report an issue: GitHub.