larksuite/cli · error
recipient %q not found in %s
Error message
recipient %q not found in %s
What it means
removeRecipient compares the requested address (case-insensitively, trimmed) against every recipient in the target field. If none matches, the header is left untouched and this error names the address and the header (To/Cc/Bcc) it was not found in.
Source
Thrown at shortcuts/mail/draft/patch.go:221
func removeRecipient(snapshot *DraftSnapshot, field, address string) error {
field = strings.ToLower(strings.TrimSpace(field))
addrs, headerName := recipientField(snapshot, field)
if len(addrs) == 0 {
return fmt.Errorf("%s header is empty", headerName)
}
needle := strings.ToLower(strings.TrimSpace(address))
next := make([]Address, 0, len(addrs))
removed := false
for _, addr := range addrs {
if strings.EqualFold(strings.TrimSpace(addr.Address), needle) {
removed = true
continue
}
next = append(next, addr)
}
if !removed {
return fmt.Errorf("recipient %q not found in %s", address, headerName)
}
setRecipientField(snapshot, headerName, next)
return nil
}
func recipientField(snapshot *DraftSnapshot, field string) ([]Address, string) {
switch field {
case "to":
return append([]Address{}, snapshot.To...), "To"
case "cc":
return append([]Address{}, snapshot.Cc...), "Cc"
case "bcc":
return append([]Address{}, snapshot.Bcc...), "Bcc"
default:
return nil, ""
}
}
View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Pass the bare email address exactly as stored, not the 'Name <addr>' form
- Read the draft's current recipients first and confirm the address and field before removing
- Handle the already-removed case as success if removal is idempotent in your workflow
Example fix
// before removeRecipient(snap, "cc", "Bob <bob@x.com>") // after removeRecipient(snap, "cc", "bob@x.com") // bare stored address, case-insensitive
Defensive patterns
Strategy: validation
Validate before calling
needle := strings.ToLower(strings.TrimSpace(address))
found := false
for _, a := range snap.Cc {
if strings.EqualFold(strings.TrimSpace(a.Address), needle) {
found = true
break
}
}
if !found { /* skip or report */ } Try / catch
if err := applyOp(op); err != nil && strings.Contains(err.Error(), "not found in") {
// treat as already-removed, continue
} Prevention
- Pass the bare stored email, never the 'Name <addr>' display form
- Fetch the draft and confirm membership before removing
- Handle repeat removals gracefully in scripts
When it happens
Trigger: A remove_recipient patch op (via applyOp) with an address string that differs from what is stored — wrong case is fine (EqualFold), but extra display-name text, different whitespace, an alias, or a wrong field will not match.
Common situations: Passing 'Bob <bob@x.com>' when only 'bob@x.com' is stored; removing from Cc when the address is in To; the recipient was already removed by a previous op; typo or outdated address from a cached list.
Related errors
- remove_attachment: %w
- replace_inline: %w
- remove_inline: %w
- header %q is protected; rerun with allow_protected_header_ed
- recipient field must be one of to/cc/bcc
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/7ae970ecdeb8b959.
Report an issue: GitHub.