tonhowtf/omniget · error

nao consegui baixar a imagem

Error message

nao consegui baixar a imagem ({})

What it means

fetch_image() iterates the candidate image URLs of a pin, downloading each and skipping videos (mp4). If every candidate fails — all HTTP errors, empty bodies, or decode failures — it raises "nao consegui baixar a imagem ({})" with the last error/status (`last`). This is an aggregate failure after exhausting all image sources for the pin.

Solutions

  1. Inspect the interpolated `last` error — it names the final HTTP status or IO failure.
  2. Retry with backoff; CDN 403/429s are often transient or header-sensitive.
  3. Ensure the HTTP client sends a browser-like User-Agent/Referer for i.pinimg.com.
  4. Verify network/proxy access to i.pinimg.com (curl one image URL directly).
  5. Skip the pin gracefully — thumbnails may still be fetchable from a smaller variant.

Example fix

// before
let (bytes, ext) = fetch_image(&pin).await?;
// after
let (bytes, ext) = fetch_image(&pin).await
    .map_err(|e| { log::warn!("image download failed: {e}"); e })
    .unwrap_or_else(|_| (Vec::new(), "missing".into())); // or skip pin
Defensive patterns

Strategy: retry

Validate before calling

// Cheap pre-flight: is the CDN reachable at all?
let ok = reqwest::get("https://i.pinimg.com/").await.map(|r| r.status().is_success()).unwrap_or(false);
anyhow::ensure!(ok, "i.pinimg.com unreachable from this network");

Type guard

null

Try / catch

let img = match fetch_image(&pin).await {
    Ok(x) => x,
    Err(e) if e.to_string().contains("403") || e.to_string().contains("429") => {
        sleep(Duration::from_secs(5)).await;
        fetch_image(&pin).await?
    }
    Err(e) => { skip_pin(&pin.id, e); return Ok(()); }
};

Prevention

When it happens

Trigger: Calling download_pin (which calls fetch_image) on a pin whose image URLs are expired CDN links (i.pinimg.com 403/404), behind a region block, or when the network/proxy blocks i.pinimg.com so every attempt fails.

Common situations: Old pins whose CDN originals were purged; scraping without Referer/User-Agent headers so Pinterest CDN returns 403; offline/proxied environments; saving to a disk already full if the last error is a write failure.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at src-tauri/omniget-core/src/core/tools/pinterest/media.rs:171

        if bytes.len() < 64 {
            last = format!("resposta vazia em {}", cand);
            continue;
        }
        let ext = sniff_ext(&bytes).unwrap_or(if ct.contains("png") {
            "png"
        } else if ct.contains("gif") {
            "gif"
        } else if ct.contains("webp") {
            "webp"
        } else {
            "jpg"
        });
        if ext == "mp4" {
            continue;
        }
        return Ok((bytes, ext));
    }
    Err(anyhow!("nao consegui baixar a imagem ({})", last))
}

fn webp_to_png(bytes: &[u8]) -> anyhow::Result<Vec<u8>> {
    let img = image::load_from_memory(bytes)?;
    let mut out = std::io::Cursor::new(Vec::new());
    img.write_to(&mut out, image::ImageFormat::Png)?;
    Ok(out.into_inner())
}

pub fn base_name(pin: &Pin, naming: &str) -> String {
    let title = pin.title.trim();
    let title = if title.is_empty() {
        pin.alt_text.trim()
    } else {
        title
    };
    let short: String = title.chars().take(70).collect();
    let clean = super::super::sanitize_name(&short);

View on GitHub (pinned to 8600b91f42)