larksuite/cli · error

no signature found in draft body

Error message

no signature found in draft body

What it means

After locating the HTML part, removeSignatureOp requires the body to contain the recognizable signature wrapper matched by signatureWrapperRe (the system-managed wrapper markup). If no wrapper is present, there is no signature block to excise, so the op fails rather than silently rewriting the HTML. This is the 'HTML exists but no signature' case.

Source

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

	// Add new signature inline images to the MIME tree.
	for _, img := range op.SignatureImages {
		addInlinePartToSnapshot(snapshot, img.Data, img.ContentType, img.FileName, img.CID)
	}

	syncTextPartFromHTML(snapshot, newHTML)
	return nil
}

// removeSignatureOp removes the signature block from the HTML body.
func removeSignatureOp(snapshot *DraftSnapshot) error {
	htmlPart := findPart(snapshot.Body, snapshot.PrimaryHTMLPartID)
	if htmlPart == nil {
		return fmt.Errorf("remove_signature: no HTML body part found")
	}
	html := string(htmlPart.Body)

	if !signatureWrapperRe.MatchString(html) {
		return fmt.Errorf("no signature found in draft body")
	}

	// Collect CIDs referenced by the signature before removing it.
	sigCIDs := collectSignatureCIDsFromHTML(html)

	// Remove signature and preceding spacing.
	html = RemoveSignatureHTML(html)

	// Remove orphaned inline parts (only if the CID is no longer referenced in remaining HTML).
	for _, cid := range sigCIDs {
		if !containsCIDIgnoreCase(html, cid) {
			removeMIMEPartByCID(snapshot.Body, cid)
		}
	}

	htmlPart.Body = []byte(html)
	htmlPart.Dirty = true

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Only call remove_signature when insert_signature previously ran on this draft
  2. Re-insert a signature via insert_signature if you need the canonical wrapper restored
  3. If the signature was hand-written, remove it by editing the HTML instead of via this op

Example fix

// before
applyOp(snapshot, PatchOp{Type: "remove_signature"}) // second time
// after
if signatureWrapperRe.MatchString(string(htmlPart.Body)) {
  applyOp(snapshot, PatchOp{Type: "remove_signature"})
}
Defensive patterns

Strategy: validation

Validate before calling

if !signatureWrapperRe.MatchString(htmlPart.Body) {
  return nil // no signature present; skip removal
}

Type guard

func hasSignature(s *DraftSnapshot) bool {
  p := findPart(s.Body, s.PrimaryHTMLPartID)
  return p != nil && signatureWrapperRe.MatchString(p.Body)
}

Try / catch

err := applyOp(snapshot, op)
if err != nil && strings.Contains(err.Error(), "no signature found in draft body") {
  return nil // idempotent: already no signature
}

Prevention

When it happens

Trigger: Applying remove_signature to a draft whose HTML body has no signature wrapper — the draft never had a signature inserted via insert_signature, or the signature markup was manually edited/removed so the regex no longer matches.

Common situations: Removing a signature twice (already removed); hand-edited HTML that dropped wrapper classes/IDs the regex depends on; a signature added by another client with different markup.

Related errors


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