zeroclaw-labs/zeroclaw · error

LinkedIn add_comment failed ({}): {}

Error message

LinkedIn add_comment failed ({}): {}

What it means

Thrown when POST of a comment to a LinkedIn post returns a non-2xx status; the raw body is embedded. Commenting requires the same social scope as posting plus a valid post URN. After this check, the response is parsed as JSON, so malformed URNs usually fail here with a 400/404 first.

Source

Thrown at crates/zeroclaw-tools/src/linkedin_client.rs:389

            "{}/rest/socialActions/{}/comments",
            LINKEDIN_API_BASE, post_id
        );

        let body = json!({
            "actor": actor_urn,
            "message": {
                "text": text
            }
        });

        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_comment failed ({}): {}", status, body_text);
        }

        let json: serde_json::Value = response
            .json()
            .await
            .context("Failed to parse add_comment response")?;

        let comment_id = json
            .get("id")
            .and_then(|v| v.as_str())
            .unwrap_or_default()
            .to_string();

        Ok(comment_id)
    }

    pub async fn add_reaction(&self, post_id: &str, reaction_type: &str) -> anyhow::Result<()> {
        let creds = self.get_credentials().await?;

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Verify the post URN format: urn:li:share:{id} (or urn:li:ugcPost:{id}) and that the post still exists.
  2. For 403, ensure w_member_social scope; for 401, refresh the token.
  3. For 404, re-list posts to get a current URN before commenting.
Defensive patterns

Strategy: try-catch

Validate before calling

// Cheap pre-check: the post must still exist before commenting
let posts = client.list_posts(&token).await?;
let still_there = posts.iter().any(|p| p.urn() == target_urn);
if !still_there { anyhow::bail!("post {target_urn} gone; skip comment"); }

Try / catch

match client.add_comment(&token, &target_urn, text).await {
    Ok(c) => Ok(c),
    Err(e) if e.to_string().contains("(404") => { /* post deleted; drop quietly */ Ok(skip()) }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Commenting on a post URN that is malformed or deleted (400/404); token lacking w_member_social (403); expired token (401); commenting on another member's post where comments are restricted.

Common situations: Using the post id returned by create_post after that post was deleted; URN strings built by concatenation with wrong prefixes (urn:li:comment vs urn:li:share); stale tokens in long-lived integrations.

Related errors


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