{"record":{"id":"ba62332c9e11969c","repo":"gitbutlerapp/gitbutler","slug":"failed-to-remove-label","errorCode":null,"errorMessage":"Failed to remove label: {}","messagePattern":"Failed to remove label: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-github/src/client.rs","lineNumber":821,"sourceCode":"        }\n\n        let labels: Vec<GitHubPrLabelApi> = response.json().await?;\n        Ok(labels.into_iter().map(Into::into).collect())\n    }\n\n    pub async fn remove_label_from_pull_request(\n        &self,\n        owner: &str,\n        repo: &str,\n        pr_number: i64,\n        label: &str,\n    ) -> Result<()> {\n        let url = label_removal_url(&self.base_url, owner, repo, pr_number, label)?;\n\n        let response = self.client.delete(url).send().await?;\n\n        if !response.status().is_success() {\n            bail!(\"Failed to remove label: {}\", response_error(response).await);\n        }\n\n        Ok(())\n    }\n\n    /// List users who can be assigned (and requested for review) on the repo.\n    pub async fn list_assignable_users(&self, owner: &str, repo: &str) -> Result<Vec<GitHubUser>> {\n        let url = format!(\"{}/repos/{}/{}/assignees\", self.base_url, owner, repo);\n\n        Ok(self\n            .get_all_pages::<GitHubApiUser>(&url, 10)\n            .await?\n            .into_iter()\n            .map(GitHubUser::from)\n            .collect())\n    }\n\n    /// Copilot's reviewer account, or `None` where the forge has none. It can","sourceCodeStart":803,"sourceCodeEnd":839,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-github/src/client.rs#L803-L839","documentation":"The label-removal function DELETEs a single label from a PR; any non-success HTTP status bails with this message and the response error body. Means GitHub refused the removal — usually the label or PR doesn't exist, or the token lacks write access.","triggerScenarios":"Calling the label removal API for a PR the token can't write to (403), a PR that doesn't exist (404), or a label name needing URL encoding that produced a bad URL (422/404).","commonSituations":"Read-only token used for a mutating call; label already removed concurrently (404); label name with spaces/slashes not URL-encoded; rate limiting.","solutions":["Check the appended response error for the exact status/cause","Ensure the token has write (pull-requests) permission","URL-encode the label name when constructing the removal URL; treat 404 as 'already removed' if removal is idempotent in your flow"],"exampleFix":"// before\nlet url = format!(\"{base}/repos/{o}/{r}/issues/{n}/labels/{label}\"); // raw label\n// after\nlet url = format!(\"{base}/repos/{o}/{r}/issues/{n}/labels/{}\", urlencode(label));","handlingStrategy":"try-catch","validationCode":"let encoded = urlencode(label);\n// optionally check label exists first:\n// GET /repos/{o}/{r}/labels/{encoded} -> 404 means nothing to remove","typeGuard":null,"tryCatchPattern":"match client.remove_label_from_pull_request(owner, repo, pr, label).await {\n    Ok(()) => (),\n    Err(e) if e.to_string().contains(\"404\") => (), // already gone: idempotent OK\n    Err(e) => return Err(e),\n}","preventionTips":["URL-encode label names in removal URLs","Treat 404 during removal as success when idempotence is desired","Ensure the token has write access; removal is a mutating call"],"tags":["github","api","labels","http","delete"],"backgroundTag":"api-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"}