{"record":{"id":"647ca0508c46d868","repo":"zeroclaw-labs/zeroclaw","slug":"interaction-reject-failed-status-err","errorCode":null,"errorMessage":"interaction reject failed ({status}): {err}","messagePattern":"interaction reject failed \\((.+?)\\): (.+?)","errorType":"http","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"crates/zeroclaw-channels/src/discord/interaction.rs","lineNumber":163,"sourceCode":"    );\n    let body = json!({\n        \"type\": 4,\n        \"data\": {\n            \"content\": message,\n            \"flags\": 64\n        }\n    });\n    // without_url: transport errors embed the token-bearing URL.\n    let resp = client\n        .post(&url)\n        .json(&body)\n        .send()\n        .await\n        .map_err(reqwest::Error::without_url)?;\n    if !resp.status().is_success() {\n        let status = resp.status();\n        let err = resp.text().await.unwrap_or_default();\n        anyhow::bail!(\"interaction reject failed ({status}): {err}\");\n    }\n    Ok(())\n}\n\npub(crate) async fn discord_edit_interaction_response(\n    client: &reqwest::Client,\n    app_id: &str,\n    interaction_token: &str,\n    api_base: &str,\n    content: &str,\n    embeds: &[DiscordEmbed],\n    components: &[DiscordActionRow],\n) -> anyhow::Result<()> {\n    let url = format!(\"{api_base}/webhooks/{app_id}/{interaction_token}/messages/@original\");\n    // No truncation: the caller chunks (deliver_interaction_answer) and this edit\n    // carries the first ≤2000-char chunk plus any embeds (EPIC C) and any\n    // interactive action rows (EPIC B). `to_rest_json` omits whichever are empty,\n    // so a plain text reply stays byte-identical.","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/discord/interaction.rs#L145-L181","documentation":"discord_reject_interaction answers a policy-refused interaction immediately with a type-4 ephemeral message (flags 64) so the invoker sees why, instead of Discord's generic \"The application did not respond\". Non-2xx becomes this error. It fails on the same grounds as other initial callbacks: token expired/unknown (handler slower than the ~3s ack window), interaction already acknowledged (e.g. a defer also fired), or invalid body such as content over 2000 chars.","triggerScenarios":"Authorization or gate checks slow enough to miss the ack window; rejecting an interaction that was already deferred or answered; rejection message longer than 2000 chars; replaying old interactions.","commonSituations":"Allowlist checks hitting remote services before rejecting; double-ack bugs where defer and reject both fire; policy messages built from verbose templates.","solutions":["Reject fast: authorization decisions should be local and immediate","Guard against double-ack — exactly one of defer/reject/modal per interaction","Keep the rejection message under 2000 chars","On 404/expired, drop the turn: the user already saw the timeout state"],"exampleFix":"// before: remote check, then reject (may miss the 3s window)\nlet ok = remote_acl(user).await?;\nif !ok { discord_reject_interaction(&client, &id, &token, msg).await?; }\n\n// after: local gate, immediate ephemeral rejection\nif !local_gate(user) {\n    discord_reject_interaction(&client, &id, &token, msg).await?;\n    return Ok(());\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if discord_reject_interaction(&client, &id, &token, reason).await.is_err() {\n    // user already saw the timeout state — log and drop the turn\n}","preventionTips":["Make authorization decisions local so rejection is immediate","Emit exactly one initial response (defer/reject/modal) per interaction","Keep rejection messages under 2000 chars"],"tags":["discord","interactions","authorization","ephemeral"],"backgroundTag":"discord-interaction-callback-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}