zeroclaw-labs/zeroclaw · error · anyhow::Error
interaction followup post failed ({status}): {err}
Error message
interaction followup post failed ({status}): {err} What it means
discord_post_interaction_followup POSTs content chunks beyond the first (replies over Discord's 2000-char limit) to {api_base}/webhooks/{app_id}/{token}. Non-2xx becomes this error. Beyond the shared token-expiry mode, this endpoint is the one most exposed to Discord rate limits (429) during multi-chunk bursts and to 50035 when a chunk itself exceeds 2000 chars after marker expansion.
Source
Thrown at crates/zeroclaw-channels/src/discord/interaction.rs:223
/// chunks beyond the first when a reply exceeds Discord's 2000-char limit.
pub(crate) async fn discord_post_interaction_followup(
client: &reqwest::Client,
app_id: &str,
interaction_token: &str,
api_base: &str,
content: &str,
) -> anyhow::Result<()> {
let url = format!("{api_base}/webhooks/{app_id}/{interaction_token}");
let resp = client
.post(&url)
.json(&DiscordOutgoing::text(content).to_rest_json())
.send()
.await
.map_err(reqwest::Error::without_url)?;
if !resp.status().is_success() {
let status = resp.status();
let err = resp.text().await.unwrap_or_default();
anyhow::bail!("interaction followup post failed ({status}): {err}");
}
Ok(())
}
#[cfg(test)]
mod embed_reply_tests {
use super::*;
use wiremock::matchers::{body_json, body_partial_json, method, path};
use wiremock::{Mock, MockServer, ResponseTemplate};
#[tokio::test]
async fn slash_reply_attaches_embeds_to_the_original_edit() {
let server = MockServer::start().await;
Mock::given(method("PATCH"))
.and(path("/webhooks/app/tok/messages/@original"))
.and(body_partial_json(serde_json::json!({
"content": "see below",
"embeds": [{ "title": "Report" }]View on GitHub (pinned to 88bb9c8533)
Solutions
- Honor 429: read retry_after from the response and delay before sending remaining chunks
- Re-chunk to ≤2000 chars after marker expansion, not before
- Deliver all chunks within the 15-minute token window — summarize if tools run long
- On 404 stop the loop: remaining chunks cannot reach that token
Example fix
// before: fire all chunks back-to-back
for chunk in chunks {
discord_post_interaction_followup(&client, app, tok, base, chunk).await?;
}
// after: honor rate limits
for chunk in chunks {
if let Err(e) = discord_post_interaction_followup(&client, app, tok, base, chunk).await {
if let Some(d) = parse_retry_after(&e) { tokio::time::sleep(d).await; continue; }
break;
}
} Defensive patterns
Strategy: retry
Try / catch
for chunk in chunks {
if let Err(e) = discord_post_interaction_followup(&client, app, tok, base, chunk).await {
if let Some(d) = parse_retry_after(&e) {
tokio::time::sleep(d).await;
continue; // honor 429 Retry-After, then resend this chunk
}
break; // 404/expired token — remaining chunks are undeliverable
}
} Prevention
- Honor 429 Retry-After on multi-chunk followups
- Chunk to ≤2000 chars after marker expansion
- Send every chunk inside the 15-minute window
When it happens
Trigger: Several followup posts in quick succession hitting per-channel rate limits without honoring Retry-After; a chunk over 2000 chars after embed/component markers are expanded; token older than 15 minutes by the time later chunks send.
Common situations: Verbose agent outputs with large tool logs; chunk sends without inter-chunk delay; late chunks after a long-running tool call crosses the TTL.
Related errors
- interaction followup edit failed ({status}): {err}
- interaction defer failed ({status}): {err}
- modal open failed ({status}): {err}
- interaction autocomplete answer failed ({status}): {err}
- interaction reject failed ({status}): {err}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/544bd48bf91b873f.
Report an issue: GitHub.