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

  1. For 404/400, re-fetch the post list and use a fresh URN.
  2. For 403, grant w_member_social and re-authorize the member.
  3. For 401, ensure a refresh token is stored so the client can renew, or re-run the OAuth flow.
  4. 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

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


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/9b19f12488516631. Report an issue: GitHub.