{"record":{"id":"8576e38fed931a4b","repo":"gitbutlerapp/gitbutler","slug":"failed-to-delete-comment","errorCode":null,"errorMessage":"Failed to delete comment: {}","messagePattern":"Failed to delete comment: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-github/src/client.rs","lineNumber":975,"sourceCode":"        let comment: GitHubIssueComment = response.json().await?;\n        Ok(comment.into())\n    }\n\n    pub async fn delete_pull_request_comment(\n        &self,\n        owner: &str,\n        repo: &str,\n        comment_id: i64,\n    ) -> Result<()> {\n        let url = format!(\n            \"{}/repos/{}/{}/issues/comments/{}\",\n            self.base_url, owner, repo, comment_id\n        );\n\n        let response = self.client.delete(&url).send().await?;\n\n        if !response.status().is_success() {\n            bail!(\n                \"Failed to delete comment: {}\",\n                response_error(response).await\n            );\n        }\n\n        Ok(())\n    }\n\n    /// List the submitted reviews on a pull request (approvals, change\n    /// requests, review comments), oldest first, each with its reactions.\n    ///\n    /// GraphQL rather than REST: a review is only reactable through\n    /// GraphQL, and `/pulls/{n}/reviews` reports neither its reactions nor\n    /// the node id the reaction mutations address.\n    pub async fn list_pull_request_reviews(\n        &self,\n        owner: &str,\n        repo: &str,","sourceCodeStart":957,"sourceCodeEnd":993,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-github/src/client.rs#L957-L993","documentation":"This error comes from `GithubClient::delete_pull_request_comment`, which DELETEs `/repos/{owner}/{repo}/issues/comments/{comment_id}`. GitHub returning a non-success status is converted to this error, meaning the comment still exists and was not deleted.","triggerScenarios":"Any `delete_pull_request_comment(owner, repo, comment_id)` call where the DELETE returns non-2xx — 404 (comment already deleted or wrong id/repo), 403 (no write permission, not the comment author, or rate limit), 401 (bad token).","commonSituations":"Double-deleting after an earlier retry actually succeeded; deleting another user's comment without moderator rights; id belongs to a different repository; token scope revoked mid-session.","solutions":["Check the status in the message: a 404 usually means the comment is already gone — treat as success if idempotency is desired.","For 403, confirm the token's user authored the comment or has admin/moderator rights.","Re-authenticate if the token is expired (401).","Verify owner/repo matches the comment's repository.","Back off and retry if rate-limited (403 with X-RateLimit-Remaining: 0)."],"exampleFix":"// before\nclient.delete_pull_request_comment(owner, repo, id).await?; // fails on already-deleted\n// after\nmatch client.delete_pull_request_comment(owner, repo, id).await {\n    Ok(()) => {},\n    Err(e) if e.to_string().contains(\"404\") => {}, // already deleted: fine\n    Err(e) => return Err(e),\n}","handlingStrategy":"try-catch","validationCode":"let comments = client.list_pull_request_comments(owner, repo, pr).await?;\nif !comments.iter().any(|c| c.id == comment_id) {\n    return Ok(()); // already deleted: no-op\n}","typeGuard":"fn can_delete(comment: &PullRequestComment, current_user: &str, is_admin: bool) -> bool {\n    comment.author_login == current_user || is_admin\n}","tryCatchPattern":"match client.delete_pull_request_comment(owner, repo, comment_id).await {\n    Ok(()) => {},\n    Err(e) if e.to_string().contains(\"404\") => {}, // already gone\n    Err(e) => return Err(e),\n}","preventionTips":["Make deletion idempotent by ignoring 404s.","Only offer delete for comments authored by the current user (or moderator).","Avoid double-click/double-submit of delete actions in UIs.","Confirm the comment belongs to the same repository before deleting."],"tags":["github-api","http-error-response","rest","network"],"backgroundTag":"http-error-response","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}