zeroclaw-labs/zeroclaw · error

QR payload is empty

Error message

QR payload is empty

What it means

`render_pairing_qr` renders the WhatsApp Web pairing QR shown at login; the code string received from the backend is trimmed and must be non-empty before QR encoding. This error means the backend emitted a pairing/QR event whose payload was blank — a protocol or backend anomaly on the login handshake, not a formatting mistake by your code.

Source

Thrown at crates/zeroclaw-channels/src/whatsapp_web.rs:1156

            .split_once('@')
            .map(|(user, _)| user)
            .unwrap_or(trimmed);
        let normalized_user = user_part.trim_start_matches('+');
        format!("+{normalized_user}")
    }

    /// Whether the recipient string is a WhatsApp JID (contains a domain suffix).
    #[cfg(feature = "whatsapp-web")]
    fn is_jid(recipient: &str) -> bool {
        recipient.trim().contains('@')
    }

    /// Render a WhatsApp pairing QR payload into terminal-friendly text.
    #[cfg(feature = "whatsapp-web")]
    fn render_pairing_qr(code: &str) -> Result<String> {
        let payload = code.trim();
        if payload.is_empty() {
            anyhow::bail!("QR payload is empty");
        }

        let qr = qrcode::QrCode::new(payload.as_bytes()).map_err(|err| {
            ::zeroclaw_log::record!(
                ERROR,
                ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)
                    .with_outcome(::zeroclaw_log::EventOutcome::Failure)
                    .with_attrs(::serde_json::json!({"error": format!("{}", err)})),
                "Failed to encode WhatsApp Web QR payload"
            );
            anyhow::Error::msg(format!("Failed to encode WhatsApp Web QR payload: {err}"))
        })?;

        Ok(qr
            .render::<qrcode::render::unicode::Dense1x2>()
            .quiet_zone(true)
            .build())
    }

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Retry the pairing flow — request a fresh QR (codes rotate on ~20s timers anyway, so a stale/blank one is usually transient).
  2. Update zeroclaw so the vendored WhatsApp Web backend tracks the current protocol.
  3. If it persists, remove the session files and pair from scratch.
Defensive patterns

Strategy: retry

Type guard

fn non_empty_qr_payload(code: &str) -> bool {
    !code.trim().is_empty()
}

Try / catch

match channel.listen(tx).await {
    Err(e) if e.to_string().contains("QR payload is empty") => {
        // transient handshake anomaly: restart listen() to request a fresh QR
        tokio::time::sleep(std::time::Duration::from_secs(5)).await;
        channel.listen(tx).await
    }
    other => other,
}

Prevention

When it happens

Trigger: During `listen()` pairing when the vendored WhatsApp Web backend delivers a QR event with an empty or whitespace-only code string, before `qrcode::QrCode::new` would even run.

Common situations: Version skew between the vendored backend and WhatsApp's current protocol; a race where the QR is requested before the handshake populates it; a corrupted initial login handshake.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/849e578beebdcdec. Report an issue: GitHub.