{"record":{"id":"307ac1b6a466b506","repo":"zeroclaw-labs/zeroclaw","slug":"recipient-cannot-be-empty","errorCode":null,"errorMessage":"Recipient cannot be empty","messagePattern":"Recipient cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/whatsapp_web.rs","lineNumber":1180,"sourceCode":"                ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)\n                    .with_outcome(::zeroclaw_log::EventOutcome::Failure)\n                    .with_attrs(::serde_json::json!({\"error\": format!(\"{}\", err)})),\n                \"Failed to encode WhatsApp Web QR payload\"\n            );\n            anyhow::Error::msg(format!(\"Failed to encode WhatsApp Web QR payload: {err}\"))\n        })?;\n\n        Ok(qr\n            .render::<qrcode::render::unicode::Dense1x2>()\n            .quiet_zone(true)\n            .build())\n    }\n\n    #[cfg(feature = \"whatsapp-web\")]\n    fn recipient_to_jid(&self, recipient: &str) -> Result<wacore_binary::jid::Jid> {\n        let trimmed = recipient.trim();\n        if trimmed.is_empty() {\n            anyhow::bail!(\"Recipient cannot be empty\");\n        }\n\n        if trimmed.contains('@') {\n            return trimmed.parse::<wacore_binary::jid::Jid>().map_err(|e| {\n                ::zeroclaw_log::record!(\n                    WARN,\n                    ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Reject)\n                        .with_outcome(::zeroclaw_log::EventOutcome::Failure)\n                        .with_attrs(::serde_json::json!({\n                            \"trimmed\": trimmed,\n                            \"error\": format!(\"{}\", e),\n                        })),\n                    \"whatsapp_web: invalid JID\"\n                );\n                anyhow::Error::msg(format!(\"Invalid WhatsApp JID `{trimmed}`: {e}\"))\n            });\n        }\n","sourceCodeStart":1162,"sourceCodeEnd":1198,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/whatsapp_web.rs#L1162-L1198","documentation":"`recipient_to_jid` converts a recipient string into a WhatsApp JID for the WhatsApp Web channel; after trimming, an empty string bails immediately with this local validation error. It is raised from the send paths (`send`, typing indicators) when `message.recipient` is blank.","triggerScenarios":"Any send or typing call whose recipient is empty or only whitespace, e.g. `SendMessage::new(text, \"\")` or a recipient field that a template variable rendered to nothing.","commonSituations":"Upstream data missing a phone number (empty DB column, unset config target); replying to an inbound event that carried no sender address; a default recipient env var that was never set.","solutions":["Require and validate a recipient before enqueueing the send.","Default to a configured admin/test number when the target is missing, if that suits your flow.","Fix the data source that produced the blank recipient."],"exampleFix":"// before\nchannel.send(&SendMessage::new(body, \"\")).await?; // blank recipient -> bails\n\n// after\nlet Some(to) = recipient else {\n    anyhow::bail!(\"no recipient available for this reply\");\n};\nchannel.send(&SendMessage::new(body, &to)).await?;","handlingStrategy":"validation","validationCode":"let to = recipient.trim();\nanyhow::ensure!(!to.is_empty(), \"recipient is required before sending\");\nchannel.send(&SendMessage::new(text, to)).await","typeGuard":"fn non_empty_recipient(recipient: &str) -> bool {\n    !recipient.trim().is_empty()\n}","tryCatchPattern":null,"preventionTips":["Validate recipients where messages enter your system (inbound handler, queue producer), not at the channel.","Alert on empty-recipient upstream events — they signal missing sender data.","Never default silently to a hard-coded recipient in production; make the miss loud."],"tags":["whatsapp-web","recipient","validation","rust"],"backgroundTag":"argument-validation-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}