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
- Only call remove_signature when insert_signature previously ran on this draft
- Re-insert a signature via insert_signature if you need the canonical wrapper restored
- 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
- Treat remove_signature as idempotent and guard with the regex first
- Do not hand-edit the signature wrapper markup the regex depends on
- Only remove signatures that were inserted via insert_signature
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
- insert_signature: no HTML body part found; use set_body firs
- remove_signature: no HTML body part found
- recipient %q not found in %s
- inline part %q not found
- attachment part %q not found
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/12785531f15d8805.
Report an issue: GitHub.