zeroclaw-labs/zeroclaw · error
LinkedIn add_reaction failed ({}): {}
Error message
LinkedIn add_reaction failed ({}): {} What it means
Thrown when POST of a reaction (like) to a LinkedIn post returns a non-2xx status, body included. Reactions need the social scope and a valid target URN; the endpoint returns no JSON payload on success, so this status check is the only failure signal. Same failure families as comments.
Source
Thrown at crates/zeroclaw-tools/src/linkedin_client.rs:423
pub async fn add_reaction(&self, post_id: &str, reaction_type: &str) -> anyhow::Result<()> {
let creds = self.get_credentials().await?;
let actor_urn = format!("urn:li:person:{}", creds.person_id);
let url = format!("{}/rest/reactions?actor={}", LINKEDIN_API_BASE, actor_urn);
let body = json!({
"reactionType": reaction_type,
"object": post_id
});
let response = self
.api_request(Method::POST, &url, &creds.access_token, Some(body))
.await?;
let status = response.status();
if !status.is_success() {
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);
}View on GitHub (pinned to 88bb9c8533)
Solutions
- For 404/400, re-fetch the post list and use a fresh URN.
- For 403, grant w_member_social and re-authorize the member.
- For 401, ensure a refresh token is stored so the client can renew, or re-run the OAuth flow.
- Rate-limit (429) reactions by backing off per LinkedIn's Retry-After guidance.
Defensive patterns
Strategy: try-catch
Try / catch
match client.add_reaction(&token, &target_urn, reaction).await {
Ok(()) => Ok(()),
Err(e) if e.to_string().contains("(404") => Ok(()), // already gone: nothing to like
Err(e) => Err(e),
} Prevention
- Treat reactions as idempotent: a 404 target means the work is done.
- Verify the URN came from the same member's feed before reacting.
- Keep the social scope on the token; reaction endpoints enforce it like posts.
When it happens
Trigger: Reacting to a deleted or malformed post URN (404/400); token missing w_member_social (403); expired token (401); rate limiting (429).
Common situations: Automation liking posts discovered via list_posts after the author deleted them; scope drift after app reconfiguration; tokens older than the 60-day lifetime.
Related errors
- LinkedIn create_post failed ({}): {}
- LinkedIn list_posts failed ({}): {}
- LinkedIn add_comment failed ({}): {}
- LinkedIn delete_post failed ({}): {}
- LinkedIn get_engagement failed ({}): {}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/9b19f12488516631.
Report an issue: GitHub.