zeroclaw-labs/zeroclaw · error

LinkedIn create_post failed ({}): {}

Error message

LinkedIn create_post failed ({}): {}

What it means

Thrown when POST to LinkedIn's /rest/posts returns a non-2xx status. The full response body is included (not truncated), which matters because LinkedIn returns detailed JSON errors. The post URN is taken from the x-restli-id header on success, so any failure status aborts before that.

Source

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

                "content".to_string(),
                json!({
                    "article": {
                        "source": url,
                        "title": article_title.unwrap_or("")
                    }
                }),
            );
        }

        let url = format!("{}/rest/posts", LINKEDIN_API_BASE);
        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 create_post failed ({}): {}", status, body_text);
        }

        // The post URN is returned in the x-restli-id header
        let post_urn = response
            .headers()
            .get("x-restli-id")
            .and_then(|v| v.to_str().ok())
            .map(String::from)
            .unwrap_or_default();

        Ok(post_urn)
    }

    pub async fn list_posts(&self, count: usize) -> anyhow::Result<Vec<PostSummary>> {
        let creds = self.get_credentials().await?;
        let author_urn = format!("urn:li:person:{}", creds.person_id);
        let url = format!(
            "{}/rest/posts?author={}&q=author&count={}",

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Read the status: 403 => add the w_member_social scope (Share on LinkedIn product) to the app and re-authorize; 401 => refresh or re-issue the token; 400 => fix the payload; 429 => back off.
  2. Ensure the author field is urn:li:person:{id} of exactly the member who authorized the token.
  3. Check that text is non-empty and visibility is 'PUBLIC' or 'CONNECTIONS' as the API requires.
  4. If posting as an organization, use urn:li:organization:{id} with the matching admin permissions.

Example fix

// before: posting with token that lacks w_member_social -> 403
client.create_post(&token, &person_urn, "Hello").await?;

// after: request the right scopes during OAuth, then post
// scopes: "openid profile w_member.social" (or legacy w_member_social)
client.create_post(&fresh_token, &format!("urn:li:person:{person_id}"), "Hello").await?;
Defensive patterns

Strategy: try-catch

Try / catch

match client.create_post(&token, &author_urn, text).await {
    Ok(urn) => Ok(urn),
    Err(e) => {
        let m = e.to_string();
        if m.contains("(403") { Err(e).context("missing w_member_social scope; re-authorize") }
        else if m.contains("(401") { Err(e).context("token expired; refresh") }
        else { Err(e) }
    }
}

Prevention

When it happens

Trigger: 403 when the token lacks the w_member_social scope; 400 when the author URN is wrong or text/visibility fields are malformed; 401 when the access token is expired and refresh did not happen or failed; 429 rate limit on posts creation.

Common situations: App configured with only r_liteprofile/r_basicprofile scopes instead of the LinkedIn API 'Share on LinkedIn' (w_member_social) product; person URN from a different member than the token owner; access tokens older than 60 days; missing refresh token so api_request could not renew.

Related errors


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