larksuite/cli · error
set_recipients requires non-empty addresses
Error message
set_recipients requires non-empty addresses
What it means
Thrown by PatchOp.Validate() in shortcuts/mail/draft/model.go:277 when a set_recipients patch op passes an Address whose value is empty or whitespace-only. The validator walks every entry in op.Addresses and requires each addr.Address to contain non-blank text. It is a client-side pre-flight check so malformed recipient entries never reach the mail draft API.
Source
Thrown at shortcuts/mail/draft/model.go:277
return nil
}
func (op PatchOp) Validate() error {
switch op.Op {
case "set_subject":
if strings.TrimSpace(op.Value) == "" {
return fmt.Errorf("set_subject requires value")
}
if strings.ContainsAny(op.Value, "\r\n") {
return fmt.Errorf("set_subject: value must not contain CR or LF")
}
case "set_recipients":
if !isRecipientField(op.Field) {
return fmt.Errorf("recipient field must be one of to/cc/bcc")
}
for _, addr := range op.Addresses {
if strings.TrimSpace(addr.Address) == "" {
return fmt.Errorf("set_recipients requires non-empty addresses")
}
}
case "add_recipient", "remove_recipient":
if !isRecipientField(op.Field) {
return fmt.Errorf("recipient field must be one of to/cc/bcc")
}
if strings.TrimSpace(op.Address) == "" {
return fmt.Errorf("%s requires address", op.Op)
}
case "set_reply_to":
if len(op.Addresses) == 0 {
return fmt.Errorf("set_reply_to requires addresses")
}
case "clear_reply_to":
case "set_body", "set_reply_body":
case "replace_body", "append_body":
if !isBodyKind(op.BodyKind) {
return fmt.Errorf("body_kind must be text/plain or text/html")View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Find the offending entry in the addresses array (the error is wrapped as invalid patch op #N, so check op N) and set its address to a real value.
- Filter out empty/whitespace entries before constructing the op: build the list with a guard like if strings.TrimSpace(a) != "".
- If a recipient is genuinely unknown, drop it from the array rather than sending a blank entry.
Example fix
// before
addresses := strings.Split(recipientList, ",")
// produces an empty entry for "a@x.com,"
// after
var addrs []Address
for _, a := range strings.Split(recipientList, ",") {
if trimmed := strings.TrimSpace(a); trimmed != "" {
addrs = append(addrs, Address{Address: trimmed})
}
} Defensive patterns
Strategy: validation
Validate before calling
for _, a := range op.Addresses {
if strings.TrimSpace(a.Address) == "" {
return fmt.Errorf("empty address in set_recipients")
}
} Type guard
func validAddresses(addrs []Address) bool {
for _, a := range addrs {
if strings.TrimSpace(a.Address) == "" {
return false
}
}
return true
} Prevention
- Split recipient lists on delimiters and trim + drop empty entries immediately.
- Never build Address entries from untrimmed template output.
- Call Patch.Validate() locally before submitting the whole patch to catch the op index early.
When it happens
Trigger: A patch op {"op":"set_recipients","field":"to","addresses":[{"address":"a@x.com"},{"address":" "}]} — any single entry in the addresses array with an empty, "", or whitespace-only address string triggers it, even if other entries are valid.
Common situations: Building the addresses array programmatically from parsed email lists where an empty string slipped through (e.g. a trailing comma in "a@x.com, b@y.com," split on commas); template interpolation that left a placeholder blank; deserializing JSON where an Address object exists but its address key was omitted or null.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- %s requires address
- set_reply_to requires addresses
- body_kind must be text/plain or text/html
- selector must be primary
- set_header requires name
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/9f7c6957a655856a.
Report an issue: GitHub.