zeroclaw-labs/zeroclaw · error

LinkedIn create_post_with_image failed ({status}): {body_tex

Error message

LinkedIn create_post_with_image failed ({status}): {body_text}

What it means

create_post_with_image POSTs the finished post (text plus the uploaded image URN) to LinkedIn's posts endpoint and bails when the HTTP status is not success, including the response body for diagnosis. It fires after image registration and byte upload already succeeded, so the problem is the post request itself: auth, author URN, visibility, or throttling.

Source

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

        if let Some(ts) = scheduled_at
            && let Ok(dt) = chrono::DateTime::parse_from_rfc3339(ts)
        {
            let epoch_ms = dt.timestamp_millis();
            body.as_object_mut().unwrap().insert(
                "scheduledPublishOptions".to_string(),
                json!({ "scheduledPublishTime": epoch_ms }),
            );
        }

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

        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)
    }

    async fn update_env_token(&self, new_token: &str) -> anyhow::Result<()> {
        let env_path = self.workspace_dir.join(".env");
        let content = tokio::fs::read_to_string(&env_path)
            .await
            .with_context(|| format!("Failed to read {}", env_path.display()))?;

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Read the status and body_text first — LinkedIn returns a specific code naming the bad field (e.g. INVALID_URN) or the throttle that was hit
  2. Confirm the author URN format (urn:li:person:{id} vs urn:li:organization:{id}) matches the token's scopes
  3. Refresh the access token and retry the whole flow with a freshly uploaded image
  4. On 429, back off: LinkedIn posting limits are per-member and per-organization daily quotas
Defensive patterns

Strategy: try-catch

Try / catch

Catch anyhow errors from create_post_with_image, parse the leading status from the message, and branch: 429 -> back off and retry later; 401/403 -> refresh token and restart the flow; 4xx -> surface the body_text to the operator.

Prevention

When it happens

Trigger: Expired access token (401); an author URN that does not match the token's member or organization (403); referencing an image URN owned by another entity; invalid visibility or persona fields in the post body (400); LinkedIn posting quotas (429).

Common situations: Posting as an organization URN with a token that only has member permissions; reusing an image URN captured from an earlier test run; long-running schedulers whose token expired between the image steps and the post step.

Related errors


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