{"record":{"id":"adddb5c2dd751966","repo":"larksuite/cli","slug":"draft-has-no-primary-body-container","errorCode":null,"errorMessage":"draft has no primary body container","messagePattern":"draft has no primary body container","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shortcuts/mail/draft/patch.go","lineNumber":436,"sourceCode":"\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}\n\tpart := findPart(snapshot.Body, partID)\n\tif part == nil {\n\t\treturn nil, fmt.Errorf(\"body part %s not found\", partID)\n\t}\n\treturn part, nil\n}\n\nfunc ensureBodyPart(snapshot *DraftSnapshot, bodyKind string) (*Part, error) {\n\tpartRef := primaryBodyRootRef(&snapshot.Body)\n\tif partRef == nil {\n\t\treturn nil, fmt.Errorf(\"draft has no primary body container\")\n\t}\n\treturn ensureBodyPartRef(partRef, bodyKind)\n}\n\nfunc primaryBodyRootRef(root **Part) **Part {\n\tif root == nil || *root == nil {\n\t\treturn root\n\t}\n\tpart := *root\n\tif strings.EqualFold(part.MediaType, \"multipart/mixed\") {\n\t\tfor idx := range part.Children {\n\t\t\tchild := part.Children[idx]\n\t\t\tif child == nil || strings.EqualFold(child.ContentDisposition, \"attachment\") {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn &part.Children[idx]\n\t\t}\n\t\tif len(part.Children) == 0 {","sourceCodeStart":418,"sourceCodeEnd":454,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/shortcuts/mail/draft/patch.go#L418-L454","documentation":"Raised by ensureBodyPart when primaryBodyRootRef cannot return a writable root reference for the body tree — concretely when the snapshot's root pointer is nil (snapshot.Body is nil), so there is no container into which a new primary body part could be created. It guards the rewrite path: even rewrite_entire_draft cannot create a body when the draft has no body container at all.","triggerScenarios":"Calling a body rewrite operation (replaceBody with allowRewrite=true) on a snapshot whose Body field is nil — e.g. a draft snapshot with no MIME body, or a snapshot whose only content was never materialized into a Part tree.","commonSituations":"Patching a freshly created/empty draft whose body tree was never built; snapshots where all body parts were removed leaving Body nil; code paths that deserialize drafts without a root part.","solutions":["Initialize snapshot.Body to a Part (e.g. a text/plain leaf or multipart/mixed container) before invoking the rewrite path.","Create the body via the draft-create flow or set the body on first creation rather than patching an empty snapshot.","If you control snapshot construction, seed the tree with newBodyLeaf(bodyKind) so ensureBodyPartRef can attach/replace it."],"exampleFix":"// before: patching an empty snapshot\nerr := rewriteBody(snapshot, \"text/html\", html) // Body == nil\n// after: seed the root first\nif snapshot.Body == nil {\n    snapshot.Body = newBodyLeaf(\"text/plain\")\n}\nerr := rewriteBody(snapshot, \"text/html\", html)","handlingStrategy":"validation","validationCode":"if snapshot.Body == nil {\n\tsnapshot.Body = newBodyLeaf(\"text/plain\") // seed a root before rewriting\n}","typeGuard":"func hasBodyRoot(s *DraftSnapshot) bool { return s != nil && s.Body != nil }","tryCatchPattern":null,"preventionTips":["Seed a body root when constructing snapshots for empty/new drafts.","Check snapshot.Body for nil before any body rewrite operation.","Build bodies at draft creation rather than patching empty snapshots."],"tags":["email","mime","draft","nil"],"backgroundTag":"draft-body-container-missing","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"}