tonhowtf/omniget · error

Post not found via GQL

Error message

Post not found via GQL

What it means

request_gql posts to Instagram's graphql/query endpoint (PolarisPostActionLoadPostQueryQuery) and looks for the media payload under data.xdt_shortcode_media (or the legacy data.shortcode_media). This error is thrown when the HTTP response succeeded but neither key exists or the value is JSON null — i.e. Instagram accepted the query but returned no media node for the requested shortcode. It usually means Instagram refused to serve the post anonymously (login wall, deleted/private post) or the GQL doc-id/headers are stale.

Solutions

  1. Verify the post is public and exists by opening it in a browser/incognito before retrying.
  2. Check that GQL_DOC_ID, x-ig-app-id and the anonymous cookie flow are up to date; update them if Instagram rotated the endpoint.
  3. Log the raw JSON response at the failure point to see whether Instagram returned an error message or challenge instead of data.
  4. Rely on the existing fallback chain (request_embed then fallback_ytdlp) — ensure the ytdlp fallback is available and up to date.
  5. Add retries with backoff for transient rate-limit responses rather than treating every failure as permanent.

Example fix

// before
let media = data.get("xdt_shortcode_media").or_else(|| data.get("shortcode_media"));
// after
let media = data
    .get("xdt_shortcode_media")
    .or_else(|| data.get("shortcode_media"))
    .filter(|m| !m.is_null())
    .with_context(|| format!("GQL returned no media for post; keys={:?}", data.as_object().map(|o| o.keys().collect::<Vec<_>>())))?;
Defensive patterns

Strategy: fallback

Validate before calling

// Rust: check the URL looks like a canonical post before calling
fn looks_like_post(url: &str) -> bool {
    url.contains("/p/") || url.contains("/reel/") || url.contains("/tv/")
}

Type guard

fn has_media_node(data: &serde_json::Value) -> bool {
    data.get("data")
        .and_then(|d| d.get("xdt_shortcode_media").or_else(|| d.get("shortcode_media")))
        .map(|m| !m.is_null())
        .unwrap_or(false)
}

Try / catch

match downloader.get_media_info(url).await {
    Ok(info) => use(info),
    Err(e) if e.to_string().contains("Post not found via GQL") => {
        // post is private/deleted or GQL schema changed; use embed or yt-dlp fallback
        fallback_extract(url).await
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling get_media_info on an Instagram post/reel whose GQL response has data but data.xdt_shortcode_media and data.shortcode_media are absent or null; non-existent or deleted shortcode; private account; Instagram rate-limiting or login-walling the anonymous query.

Common situations: Instagram changed the GraphQL schema or doc_id so the key was renamed; the anonymous cookie/app-id became invalid; post is from a private account; post was deleted between URL validation and fetch; heavy scraping caused a soft-block returning an empty data object.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at src-tauri/omniget-core/src/platforms/instagram.rs:438

            .await?;

        if !response.status().is_success() {
            return Err(anyhow!("Instagram GQL retornou HTTP {}", response.status()));
        }

        let json: serde_json::Value = response.json().await?;

        let data = json
            .get("data")
            .ok_or_else(|| anyhow!("Resposta GQL sem data"))?;

        let media = data
            .get("xdt_shortcode_media")
            .or_else(|| data.get("shortcode_media"));

        match media {
            Some(m) if !m.is_null() => Ok(m.clone()),
            _ => Err(anyhow!("Post not found via GQL")),
        }
    }

    async fn request_embed(&self, post_id: &str) -> anyhow::Result<serde_json::Value> {
        let url = format!("https://www.instagram.com/p/{}/embed/captioned/", post_id);

        let response = self
            .client
            .get(&url)
            .header(
                "Accept",
                "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
            )
            .header("Accept-Language", "en-GB,en;q=0.9")
            .header("Sec-Fetch-Dest", "iframe")
            .header("Sec-Fetch-Mode", "navigate")
            .header("Sec-Fetch-Site", "cross-site")
            .header("Referer", "https://www.instagram.com/")

View on GitHub (pinned to 8600b91f42)