{"record":{"id":"a28a1a308b165b9b","repo":"zeroclaw-labs/zeroclaw","slug":"linkedin-delete-post-failed","errorCode":null,"errorMessage":"LinkedIn delete_post failed ({}): {}","messagePattern":"LinkedIn delete_post failed \\((.+?)\\): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-tools/src/linkedin_client.rs","lineNumber":440,"sourceCode":"            let body_text = response.text().await.unwrap_or_default();\n            anyhow::bail!(\"LinkedIn add_reaction failed ({}): {}\", status, body_text);\n        }\n\n        Ok(())\n    }\n\n    pub async fn delete_post(&self, post_id: &str) -> anyhow::Result<()> {\n        let creds = self.get_credentials().await?;\n        let url = format!(\"{}/rest/posts/{}\", LINKEDIN_API_BASE, post_id);\n\n        let response = self\n            .api_request(Method::DELETE, &url, &creds.access_token, None)\n            .await?;\n\n        let status = response.status();\n        if !status.is_success() {\n            let body_text = response.text().await.unwrap_or_default();\n            anyhow::bail!(\"LinkedIn delete_post failed ({}): {}\", status, body_text);\n        }\n\n        Ok(())\n    }\n\n    pub async fn get_engagement(&self, post_id: &str) -> anyhow::Result<EngagementSummary> {\n        let creds = self.get_credentials().await?;\n        let url = format!(\"{}/rest/socialActions/{}\", LINKEDIN_API_BASE, post_id);\n\n        let response = self\n            .api_request(Method::GET, &url, &creds.access_token, None)\n            .await?;\n\n        let status = response.status();\n        if !status.is_success() {\n            let body_text = response.text().await.unwrap_or_default();\n            anyhow::bail!(\"LinkedIn get_engagement failed ({}): {}\", status, body_text);\n        }","sourceCodeStart":422,"sourceCodeEnd":458,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-tools/src/linkedin_client.rs#L422-L458","documentation":"Thrown when DELETE of a LinkedIn post returns a non-2xx status, body included. Deletion requires the token owner to be the author of the post (or an organization admin for company posts); otherwise LinkedIn answers 403. A successful delete returns 204, so this guard is the sole failure path.","triggerScenarios":"Deleting a post URN that no longer exists (404); deleting a post authored by a different member with this member's token (403); token lacking management scope; expired token (401).","commonSituations":"Cleanup jobs deleting posts from a list captured days earlier; switching the authorized member between creation and deletion; deleting organization posts without admin rights.","solutions":["Confirm the post was created by the same member whose token is in use.","Treat 404 as success in idempotent cleanup code (post already gone).","For 403 on company posts, use a token from an organization admin.","For 401, refresh the token."],"exampleFix":"// before\nclient.delete_post(&post_urn).await?; // aborts on already-deleted 404\n\n// after: treat missing post as done\nmatch client.delete_post(&post_urn).await {\n    Ok(()) => {}\n    Err(e) if e.to_string().contains(\"404\") => { /* already deleted */ }\n    Err(e) => return Err(e),\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Idempotent delete: 404 is success\nmatch client.delete_post(&token, &post_urn).await {\n    Ok(()) => Ok(()),\n    Err(e) if e.to_string().contains(\"(404\") => Ok(()),\n    Err(e) if e.to_string().contains(\"(403\") => Err(e).context(\"not the post author; use author's token\"),\n    Err(e) => Err(e),\n}","preventionTips":["Only attempt deletes with a token from the member (or org admin) that created the post.","Record which member authored each stored post URN so cleanup uses the right token.","In scheduled cleanup, swallow 404 and alert on 403."],"tags":["linkedin","http-status","delete-post","idempotency"],"backgroundTag":"http-error-response","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}