tonhowtf/omniget · error

para desfazer saves informe os cookies da sua sessao (com…

Error message

para desfazer saves informe os cookies da sua sessao (com csrftoken)

What it means

unsave() performs an authenticated POST to PinResource/delete, which requires the csrftoken from the user's Pinterest session cookies. The client's stored `csrf` Option is None, so the call fails fast with this message before making any network request. It is a precondition error: write operations simply cannot proceed without session credentials.

Solutions

  1. Re-create the client with full session cookies copied from a logged-in browser session (must include csrftoken).
  2. Check the cookie string actually contains `csrftoken=...` before constructing the client.
  3. Re-export cookies if the Pinterest session expired and csrftoken was rotated.
  4. Gate the unsave feature in UI code behind a check that cookies are configured.

Example fix

// before
let api = PinterestApi::new(None); // no cookies
api.unsave(&pin_id).await?;
// after
let cookies = env::var("PINTEREST_COOKIES")?;
anyhow::ensure!(cookies.contains("csrftoken="), "cookies must include csrftoken");
let api = PinterestApi::new(Some(cookies));
api.unsave(&pin_id).await?;
Defensive patterns

Strategy: validation

Validate before calling

fn cookies_have_csrf(cookies: &str) -> bool {
    cookies.split(';').any(|c| c.trim().starts_with("csrftoken="))
}

Type guard

null

Try / catch

match api.unsave(&pin_id).await {
    Err(e) if e.to_string().contains("csrftoken") => {
        prompt_user("Paste cookies including csrftoken");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling PinterestApi::unsave(pin_id) on a client built without cookies, or with cookies that lack the csrftoken entry.

Common situations: Users configured the app for read-only scraping (anonymous client) and then try a write action; cookies pasted from a browser export missing csrftoken; cookies cleared on app restart.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/d4fe46b5737dc130. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/omniget-core/src/core/tools/pinterest/api.rs:1243

                break;
            }
            let r = self.http.get(&loc).send().await?;
            match r
                .headers()
                .get(reqwest::header::LOCATION)
                .and_then(|v| v.to_str().ok())
            {
                Some(l) => loc = l.to_string(),
                None => break,
            }
        }
        Ok(loc.split("/sent/").next().unwrap_or(&loc).to_string())
    }

    /// Desfaz o save de um pin seu (exige cookies com `csrftoken`).
    pub async fn unsave(&self, pin_id: &str) -> anyhow::Result<()> {
        let csrf = self.csrf.clone().ok_or_else(|| {
            anyhow!("para desfazer saves informe os cookies da sua sessao (com csrftoken)")
        })?;
        let data = json!({ "options": { "id": pin_id }, "context": {} }).to_string();
        let req = self
            .http
            .post(format!("{}/resource/PinResource/delete/", ROOT))
            .header("X-CSRFToken", csrf)
            .header("Content-Type", "application/x-www-form-urlencoded")
            .form(&[("source_url", format!("/pin/{}/", pin_id)), ("data", data)]);
        let resp = self.apply_cookie(req).send().await?;
        let status = resp.status();
        let body: Value = resp.json().await.unwrap_or(Value::Null);
        if !status.is_success() || body["resource_response"]["status"].as_str() != Some("success") {
            let msg = body["resource_response"]["error"]["message"]
                .as_str()
                .unwrap_or("falhou");
            return Err(anyhow!(
                "nao consegui desfazer o save de {} (HTTP {}): {}",
                pin_id,

View on GitHub (pinned to 8600b91f42)