larksuite/cli · error

draft has no MIME body

Error message

draft has no MIME body

What it means

removeAttachment throws this when the draft snapshot has no MIME body at all (snapshot.Body is nil), so there is no attachment tree to search. A draft without MIME parts cannot have attachments removed.

Source

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

	part := findPart(snapshot.Body, partID)
	if part == nil {
		return fmt.Errorf("inline part %q not found", partID)
	}
	if !isInlinePart(part) {
		return fmt.Errorf("part %q is not an inline MIME part", partID)
	}
	if snapshot.Body == nil || snapshot.Body.PartID == partID {
		return fmt.Errorf("cannot remove root MIME part")
	}
	if !removePart(snapshot.Body, partID) {
		return fmt.Errorf("inline part %q not found", partID)
	}
	return nil
}

func removeAttachment(snapshot *DraftSnapshot, partID string) error {
	if snapshot.Body == nil {
		return fmt.Errorf("draft has no MIME body")
	}
	part := findPart(snapshot.Body, partID)
	if part == nil {
		return fmt.Errorf("attachment part %q not found", partID)
	}
	if strings.EqualFold(part.ContentDisposition, "inline") || part.ContentID != "" {
		return fmt.Errorf("part %q is an inline MIME part; use remove_inline", partID)
	}
	if snapshot.Body.PartID == partID {
		return fmt.Errorf("cannot remove root MIME part")
	}
	removed := removePart(snapshot.Body, partID)
	if !removed {
		return fmt.Errorf("attachment part %q not found", partID)
	}
	return nil
}

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Confirm with a fresh draft get that the draft actually has MIME parts
  2. Add content/attachments first; you cannot remove from an empty body
  3. Skip the removal if the draft has no attachments (nothing to do)
  4. If the draft should have parts, recreate it with the intended body and attachments

Example fix

// before
lark mail draft patch --draft-id D --remove-attachment part_id=a_1   # empty draft
// after
lark mail draft get --draft-id D   # verify attachments exist first
lark mail draft patch --draft-id D --remove-attachment part_id=<existing>
Defensive patterns

Strategy: validation

Validate before calling

snap, _ := draftGet(draftID)
if snap.Body == nil {
    return errors.New("draft has no MIME body; nothing to remove")
}

Type guard

func hasBody(snap *DraftSnapshot) bool { return snap != nil && snap.Body != nil }

Try / catch

if err := removeAttachment(...); err != nil {
    if strings.Contains(err.Error(), "no MIME body") {
        return nil // nothing to remove
    }
    return err
}

Prevention

When it happens

Trigger: applyOp -> removeAttachment on a draft whose body was never initialized as MIME (empty draft, plain-text draft, or snapshot taken before any part was added).

Common situations: Removing attachments from a freshly created empty draft; draft downgraded to plain text; operating on a snapshot fetched before body creation.

Related errors


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