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
- 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.
- Ensure the author field is urn:li:person:{id} of exactly the member who authorized the token.
- Check that text is non-empty and visibility is 'PUBLIC' or 'CONNECTIONS' as the API requires.
- 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
- Request w_member_social (plus openid profile) at authorization time; verify scopes before first post.
- Keep the refresh token stored so api_request can renew expired access tokens.
- Build the author URN from get_profile().id of the same member who owns the token.
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
- LinkedIn image register failed ({status}): {body_text}
- LinkedIn list_posts failed ({}): {}
- LinkedIn add_comment failed ({}): {}
- LinkedIn add_reaction failed ({}): {}
- LinkedIn delete_post failed ({}): {}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/0acdd8d05ad52f6a.
Report an issue: GitHub.