larksuite/cli · error

rewrite_entire_draft cannot synthesize body inside %q

Error message

rewrite_entire_draft cannot synthesize body inside %q

What it means

During body synthesis, the recursive ensureBodyPartRef walked into a multipart container it does not understand (anything other than multipart/alternative or multipart/related, e.g. multipart/mixed as a body child or multipart/digest, multipart/signed). The rewrite_entire_draft path only knows how to synthesize a text body inside alternative/related containers, so it fails explicitly with the offending media type.

Source

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

		for idx := range part.Children {
			child := part.Children[idx]
			if child == nil {
				continue
			}
			if child.IsMultipart() && strings.EqualFold(child.MediaType, "multipart/alternative") {
				return ensureBodyPartRef(&part.Children[idx], bodyKind)
			}
		}
		if len(part.Children) == 0 {
			leaf := newBodyLeaf(bodyKind)
			part.Children = append(part.Children, leaf)
			part.Dirty = true
			leaf.Dirty = true
			return leaf, nil
		}
		return ensureBodyPartRef(&part.Children[0], bodyKind)
	default:
		return nil, fmt.Errorf("rewrite_entire_draft cannot synthesize body inside %q", part.MediaType)
	}
}

func newBodyLeaf(bodyKind string) *Part {
	return &Part{
		MediaType:        strings.ToLower(bodyKind),
		MediaParams:      map[string]string{"charset": "UTF-8"},
		TransferEncoding: "7bit",
		Headers: []Header{
			{Name: "Content-Type", Value: mime.FormatMediaType(strings.ToLower(bodyKind), map[string]string{"charset": "UTF-8"})},
			{Name: "Content-Transfer-Encoding", Value: "7bit"},
		},
		Body: []byte{},
	}
}

func newMultipartContainer(mediaType string) *Part {
	boundary := newBoundary()

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Flatten unusual nesting so the body path contains only multipart/alternative and multipart/related before rewriting.
  2. Rebuild the draft without signed/encrypted wrapping if you need programmatic body rewrite (signing can be reapplied after).
  3. Handle the offending container manually: locate the text leaf yourself and patch its Body directly instead of using the synthesis path.

Example fix

// before: multipart/related whose child is multipart/mixed
related.Children[0] = mixedContainer
// after: keep only supported nesting
related.Children[0] = altContainer // multipart/alternative
Defensive patterns

Strategy: validation

Validate before calling

func supportedBodyTree(p *Part) bool {
	if p == nil { return true }
	if p.IsMultipart() {
		mt := strings.ToLower(p.MediaType)
		if mt != "multipart/alternative" && mt != "multipart/related" && mt != "multipart/mixed" { return false }
		for _, c := range p.Children { if !supportedBodyTree(c) { return false } }
	}
	return true
}
if !supportedBodyTree(snapshot.Body) { /* flatten or rebuild before rewrite */ }

Type guard

func synthesizableContainer(p *Part) bool {
	mt := strings.ToLower(p.MediaType)
	return mt == "multipart/alternative" || mt == "multipart/related"
}

Prevention

When it happens

Trigger: Rewriting a draft whose body root descends into an unsupported multipart subtype — e.g. primaryBodyRootRef resolves to a multipart/mixed child that is itself multipart/mixed, or the first child of a multipart/related is multipart/signed or multipart/mixed.

Common situations: Drafts produced by other mail clients with nested multipart/mixed inside related containers; signed/encrypted (multipart/signed, multipart/encrypted) drafts; hand-built MIME trees with unusual nesting.

Related errors


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