{"record":{"id":"7f163e99f8178981","repo":"zeroclaw-labs/zeroclaw","slug":"discord-gate-prompt-finalize-failed-status","errorCode":null,"errorMessage":"Discord gate-prompt finalize failed ({status})","messagePattern":"Discord gate-prompt finalize failed \\((.+?)\\)","errorType":"http","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/discord/mod.rs","lineNumber":4049,"sourceCode":"            // Transient failure: put the failed and unattempted records back so a\n            // later terminal event (a stale click's \"window has passed\") retries.\n            let resp = match resp {\n                Ok(resp) => resp,\n                Err(e) => {\n                    gate_prompts::record(reference, record);\n                    for remaining in records {\n                        gate_prompts::record(reference, remaining);\n                    }\n                    return Err(e.into());\n                }\n            };\n            if !resp.status().is_success() {\n                let status = resp.status();\n                gate_prompts::record(reference, record);\n                for remaining in records {\n                    gate_prompts::record(reference, remaining);\n                }\n                anyhow::bail!(\"Discord gate-prompt finalize failed ({status})\");\n            }\n        }\n        Ok(true)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn effective_recipient_prefers_per_message_target() {\n        let ids = vec![\"fallback_channel\".to_string()];\n        assert_eq!(\n            effective_discord_recipient(\"explicit_channel\", &ids),\n            Some(\"explicit_channel\")\n        );\n    }","sourceCodeStart":4031,"sourceCodeEnd":4067,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/discord/mod.rs#L4031-L4067","documentation":"finalize_gate_prompt PATCHes each recorded gate-prompt message on Discord (appending the outcome under the original description and clearing the buttons via an explicit empty components array). When Discord answers non-2xx, the failed record and all unattempted records are put back into the process-wide gate_prompts registry and the function bails. A later terminal event (e.g. a stale button click's 'window has passed') retries the finalize.","triggerScenarios":"The PATCH to /channels/{channel_id}/messages/{message_id} returns non-success while finalizing: 403 (bot lost Send Messages / edit permission in that channel), 404 (prompt message deleted), 401 (bot token reset), or a 5xx.","commonSituations":"A moderator deletes the approval prompt before the agent answers; the bot is kicked from the guild or loses channel permissions mid-flow; the bot token is regenerated while prompts are pending; transient Discord 5xx.","solutions":["Read the embedded status: 404 means the prompt message is gone; prune that reference's gate-prompt records if you operate the registry, otherwise it will keep failing","403 → re-grant the bot View Channel / Send Messages / Read Message History in the prompt channel and let the next terminal event retry","401 → restore a valid bot token and reconnect; records were preserved so finalize retries","5xx → do nothing: records were re-recorded and a later event retries the PATCH"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match channel.finalize_gate_prompt(reference, outcome).await {\n    Ok(_) => {}\n    Err(e) if e.to_string().contains(\"gate-prompt finalize failed\") => {\n        // records were re-recorded by the channel; retry happens on the next terminal event\n        tracing::warn!(\"gate-prompt finalize deferred: {e}\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Keep the bot's edit permissions intact in gate-prompt channels; deleting prompt messages out from under the bot guarantees finalize failures","Treat finalize failures as deferred work — the registry preserves records for retry, so alert but do not drop state","Monitor repeated failures on the same reference and prune records that are provably dead (message deleted, guild left)"],"tags":["discord","gate-prompt","http-status","finalize","retryable"],"backgroundTag":"discord-api-error","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}