zeroclaw-labs/zeroclaw · error
LinkedIn delete_post failed ({}): {}
Error message
LinkedIn delete_post failed ({}): {} What it means
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.
Source
Thrown at crates/zeroclaw-tools/src/linkedin_client.rs:440
let body_text = response.text().await.unwrap_or_default();
anyhow::bail!("LinkedIn add_reaction failed ({}): {}", status, body_text);
}
Ok(())
}
pub async fn delete_post(&self, post_id: &str) -> anyhow::Result<()> {
let creds = self.get_credentials().await?;
let url = format!("{}/rest/posts/{}", LINKEDIN_API_BASE, post_id);
let response = self
.api_request(Method::DELETE, &url, &creds.access_token, None)
.await?;
let status = response.status();
if !status.is_success() {
let body_text = response.text().await.unwrap_or_default();
anyhow::bail!("LinkedIn delete_post failed ({}): {}", status, body_text);
}
Ok(())
}
pub async fn get_engagement(&self, post_id: &str) -> anyhow::Result<EngagementSummary> {
let creds = self.get_credentials().await?;
let url = format!("{}/rest/socialActions/{}", LINKEDIN_API_BASE, post_id);
let response = self
.api_request(Method::GET, &url, &creds.access_token, None)
.await?;
let status = response.status();
if !status.is_success() {
let body_text = response.text().await.unwrap_or_default();
anyhow::bail!("LinkedIn get_engagement failed ({}): {}", status, body_text);
}View on GitHub (pinned to 88bb9c8533)
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.
Example fix
// before
client.delete_post(&post_urn).await?; // aborts on already-deleted 404
// after: treat missing post as done
match client.delete_post(&post_urn).await {
Ok(()) => {}
Err(e) if e.to_string().contains("404") => { /* already deleted */ }
Err(e) => return Err(e),
} Defensive patterns
Strategy: try-catch
Try / catch
// Idempotent delete: 404 is success
match client.delete_post(&token, &post_urn).await {
Ok(()) => Ok(()),
Err(e) if e.to_string().contains("(404") => Ok(()),
Err(e) if e.to_string().contains("(403") => Err(e).context("not the post author; use author's token"),
Err(e) => Err(e),
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: Cleanup jobs deleting posts from a list captured days earlier; switching the authorized member between creation and deletion; deleting organization posts without admin rights.
Related errors
- LinkedIn create_post failed ({}): {}
- LinkedIn list_posts failed ({}): {}
- LinkedIn add_comment failed ({}): {}
- LinkedIn add_reaction failed ({}): {}
- LinkedIn get_engagement failed ({}): {}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/a28a1a308b165b9b.
Report an issue: GitHub.