zeroclaw-labs/zeroclaw · error
LinkedIn get_engagement failed ({}): {}
Error message
LinkedIn get_engagement failed ({}): {} What it means
Thrown when GET of a post's engagement statistics returns non-2xx, body included. Engagement endpoints are restricted: tokens typically need the correct product/scope, and organizational analytics require additional permissions. The parsed JSON is then shaped into an EngagementSummary, so shape problems surface after this check.
Source
Thrown at crates/zeroclaw-tools/src/linkedin_client.rs:457
let body_text = response.text().await.unwrap_or_default();
anyhow::bail!("LinkedIn delete_post failed ({}): {}", status, body_text);
}
Ok(())
}
pub async fn get_engagement(&self, post_id: &str) -> anyhow::Result<EngagementSummary> {
let creds = self.get_credentials().await?;
let url = format!("{}/rest/socialActions/{}", LINKEDIN_API_BASE, post_id);
let response = self
.api_request(Method::GET, &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 get_engagement failed ({}): {}", status, body_text);
}
let json: serde_json::Value = response
.json()
.await
.context("Failed to parse get_engagement response")?;
let likes = json
.get("likesSummary")
.and_then(|v| v.get("totalLikes"))
.and_then(|v| v.as_u64())
.unwrap_or(0);
let comments = json
.get("commentsSummary")
.and_then(|v| v.get("totalFirstLevelComments"))
.and_then(|v| v.as_u64())
.unwrap_or(0);View on GitHub (pinned to 88bb9c8533)
Solutions
- For 403, request the analytics product/scope for the app and re-authorize.
- Ensure the URN matches the post type you created (share vs ugcPost vs posts API URN).
- For 401, refresh the token; for 429, lengthen the polling interval.
- Only query posts owned by the authorized member or organization.
Defensive patterns
Strategy: try-catch
Try / catch
match client.get_engagement(&token, &post_urn).await {
Ok(stats) => record(stats),
Err(e) if e.to_string().contains("(403") => { /* analytics not granted; degrade silently or alert once */ }
Err(e) if e.to_string().contains("(429") => { /* back off polling */ }
Err(e) => return Err(e),
} Prevention
- Poll engagement at a low fixed cadence to avoid 429s.
- Request analytics products/scopes up front if dashboards need them.
- Store the URN kind (share vs ugcPost) with the post so stats queries use the right one.
When it happens
Trigger: Fetching engagement for a post the token's member does not own; missing analytics scope (403); expired token (401); deleted post (404); using share statistics endpoints on ugcPost URNs or vice versa.
Common situations: Dashboards polling metrics with tokens granted only for posting; URN kind mismatches after LinkedIn's share/ugcPost migration; rate limits on frequent polling.
Related errors
- LinkedIn create_post failed ({}): {}
- 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/0a3122b92eb605d7.
Report an issue: GitHub.