zeroclaw-labs/zeroclaw · error · anyhow::Error
DM failed ({status}): {body}
Error message
DM failed ({status}): {body} What it means
Raised by RedditChannel::send on the direct-message branch when POST {REDDIT_API_BASE}/api/compose returns a non-2xx status; the response body is included verbatim. Reddit reports DM failures through this endpoint with 429 rate limits ('you are doing that too much'), 400 validation errors (missing subject/recipient, NO_VERIFIED_EMAIL on the target), and 403 when the recipient has blocked the bot or the bot lacks PM permissions. It only fires for DM sends, not comment replies.
Source
Thrown at crates/zeroclaw-channels/src/reddit.rs:327
let resp = client
.post(format!("{REDDIT_API_BASE}/api/compose"))
.bearer_auth(&token)
.header("User-Agent", USER_AGENT)
.form(&[
("to", message.recipient.as_str()),
("subject", subject),
("text", &message.content),
])
.send()
.await?;
let status = resp.status();
if !status.is_success() {
let body = resp
.text()
.await
.unwrap_or_else(|e| format!("<failed to read response: {e}>"));
bail!("DM failed ({status}): {body}");
}
}
Ok(())
}
async fn listen(&self, tx: tokio::sync::mpsc::Sender<ChannelMessage>) -> Result<()> {
// Initial auth
self.refresh_access_token().await?;
let scope = if self.subreddits.is_empty() {
String::new()
} else {
format!(
"in {}",
self.subreddits
.iter()
.map(|s| format!("r/{s}"))View on GitHub (pinned to 88bb9c8533)
Solutions
- On 429/'too much': back off for several minutes — compose limits are stricter than comment limits
- Validate the recipient username and ensure the target account can receive PMs (verified email)
- On 401, refresh the access token; on repeated 403, test manually to see if the account is blocked or restricted
- Queue outbound DMs and drip-feed them instead of bursting
Defensive patterns
Strategy: retry
Try / catch
if let Err(err) = channel.send(&recipient, &dm).await {
let msg = format!("{err:#}");
if msg.starts_with("DM failed (429") || msg.contains("too much") {
enqueue_with_delay(dm, Duration::from_secs(600)); // drip-feed, don't fail
return Ok(());
}
return Err(err);
} Prevention
- Queue DMs and send them with spacing — compose limits are stricter than comment limits
- Verify recipient usernames and that targets can receive PMs (verified email)
- On persistent 403, stop sending to that user: likely blocked or restricted
When it happens
Trigger: send() runs the else-branch (Direct message) building /api/compose with to/subject/text; any non-success status triggers the bail at reddit.rs:327.
Common situations: Bots mass-DMing users and tripping Reddit's much stricter compose rate limits; target user has no verified email (Reddit rejects composing to them); bot account too young/low-karma for the compose API; recipient username typo'd or deleted; blocked by the recipient.
Related errors
- comment reply failed ({status}): {body}
- token refresh failed ({status}): {body}
- channel does not support room creation
- Discord send message failed ({status}): {err}
- send failed {context}: status={status}, body={body}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/a8f9d321093e6013.
Report an issue: GitHub.