zeroclaw-labs/zeroclaw · error
WhatsApp location marker must be `lat,lng[,name[,address]]`
Error message
WhatsApp location marker must be `lat,lng[,name[,address]]` with in-range WGS84 coordinates
What it means
The WhatsApp Cloud `send` path extracts `[LOCATION:...]` attachment markers from message content and converts each into a native location pin. Each marker target must parse as `lat,lng[,name[,address]]` with WGS84-range coordinates (latitude -90..=90, longitude -180..=180). This error fires only when every marker in the message failed to parse AND no plain text remains — i.e. nothing was sendable at all. Malformed markers mixed with real text are logged (WARN, reason `invalid_location`) and skipped, and the send still succeeds.
Source
Thrown at crates/zeroclaw-channels/src/whatsapp.rs:844
let mut failed_markers = 0usize;
for (_, target) in &location_markers {
match crate::util::WhatsAppLocation::parse(target) {
Some(loc) => self.post_message(location_message_body(to, &loc)).await?,
None => {
::zeroclaw_log::record!(
WARN,
::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Reject)
.with_outcome(::zeroclaw_log::EventOutcome::Failure)
.with_attrs(::serde_json::json!({"reason": "invalid_location"})),
"whatsapp: location marker target is malformed or outside WGS84 range"
);
failed_markers += 1;
}
}
}
if failed_markers == location_markers.len() && text.is_empty() {
anyhow::bail!(
"WhatsApp location marker must be `lat,lng[,name[,address]]` with in-range WGS84 coordinates"
);
}
Ok(())
}
async fn send_choice(
&self,
recipient: &str,
prompt: &str,
options: &[(String, String)],
) -> anyhow::Result<()> {
let trimmed_prompt = prompt.trim();
// No options → send the prompt as plain text (or no-op when both
// empty); never render a "(reply with name or number)" hint with
// nothing under it. Mirrors the trait default's empty guard.
if options.is_empty() {View on GitHub (pinned to 88bb9c8533)
Solutions
- Fix the marker target format: `lat,lng` plus optional quoted `name` and `address` fields, with lat in -90..=90 and lng in -180..=180.
- Include plain text alongside markers so one bad pin cannot make the entire message fail.
- Validate coordinates at the source (template/LLM tooling) before building the marker.
Example fix
// before let content = "[LOCATION:91.0,0.0]"; // lat out of WGS84 range channel.send(&SendMessage::new(content, to)).await?; // after let content = "Meet me here: [LOCATION:40.7128,-74.0060,\"Statue of Liberty\",\"New York, NY\"]"; channel.send(&SendMessage::new(content, to)).await?;
Defensive patterns
Strategy: validation
Validate before calling
fn valid_location_target(t: &str) -> bool {
let mut parts = t.split(',');
let lat = parts.next().and_then(|p| p.trim().parse::<f64>().ok());
let lng = parts.next().and_then(|p| p.trim().parse::<f64>().ok());
matches!((lat, lng),
(Some(la), Some(lo))
if (-90.0..=90.0).contains(&la) && (-180.0..=180.0).contains(&lo))
}
// before sending, check every LOCATION marker in the content
assert!(extract_location_targets(&content).iter().all(|t| valid_location_target(t))); Type guard
fn looks_like_location_target(target: &str) -> bool {
let mut parts = target.split(',');
let lat = parts.next().and_then(|p| p.trim().parse::<f64>().ok());
let lng = parts.next().and_then(|p| p.trim().parse::<f64>().ok());
matches!((lat, lng), (Some(la), Some(lo))
if (-90.0..=90.0).contains(&la) && (-180.0..=180.0).contains(&lo))
} Try / catch
match channel.send(&msg).await {
Err(e) if e.to_string().contains("location marker must be") => {
// degrade gracefully: strip markers, deliver plain text
let plain = strip_location_markers(&msg.content);
channel.send(&SendMessage::new(plain, &msg.recipient)).await
}
other => other,
} Prevention
- Always emit marker content with a plain-text lead-in so one bad pin never fails the whole send.
- Quote names/addresses containing commas (`[LOCATION:40.7,-74,"ACME, Inc."]`).
- If an LLM generates markers, constrain the tool schema to `lat: number, lng: number` with documented ranges.
When it happens
Trigger: A `SendMessage` whose content consists solely of location markers, all malformed: `[LOCATION:40.7128]` (missing longitude), `[LOCATION:91.0,0.0]` (latitude out of range), `[LOCATION:not-a-number,0.0]`, or an empty marker target.
Common situations: An LLM or template emitting only one coordinate; decimal-comma locales producing `40,7128,-74,0060`; latitude/longitude swapped or scaled wrongly; forgetting that names containing commas must be quoted (`[LOCATION:40.7,-74,"ACME, Inc."]` is valid).
Related errors
- WhatsApp interactive buttons require 1..=3 options (got {});
- WhatsApp interactive list requires at least one section
- WhatsApp interactive list capped at 10 sections (got {})
- WhatsApp interactive list section '{}' capped at 10 rows (go
- WhatsApp send_choice: {} options exceeds list cap ({}); spli
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/2253d6bec372e1d2.
Report an issue: GitHub.