vlayer logovlayer

Scraping errors

Error codes returned when a post or profile cannot be read, and which ones are safe to retry.

Routes that read from Instagram or TikTok can fail because the post or profile is not readable. They return the standard error envelope; branch on error, never on message.

{
  "error": "POST_AGE_RESTRICTED",
  "message": "This post is age-restricted, so it cannot be scraped. Ask the creator to repost without an age restriction."
}
errorHTTPRetry?Meaning
POST_AGE_RESTRICTED422NoThe post is age-gated. Only its author can fix this by reposting without the restriction
POST_NOT_ACCESSIBLE422NoThe post is private or otherwise not public
POST_NOT_FOUND404NoThe post no longer exists at that URL
SCRAPING_RATE_LIMITED429YesWait for the Retry-After header, then retry
SCRAPING_UNAVAILABLE503LaterScraping is temporarily down
SCRAPING_ERROR502YesScraping failed for an unclassified reason

422 and 404 are permanent for that URL. Retrying them will not change the result; fix the post or replace the campaign. 429, 502, and 503 are transient.

Routes that return these codes

Liker fetching reports failures on the run's status and errorMessage instead; see Instagram likers.

Handling pattern

const res = await fetch(`${API_BASE_URL}/admin/challenges/${challengeId}/comments/refresh`, {
  method: "POST",
  headers: { Authorization: `Bearer ${API_TOKEN}` },
});

if (res.ok) return (await res.json()).data;

const { error } = await res.json();
switch (error) {
  case "SCRAPING_RATE_LIMITED":
    return retryAfter(Number(res.headers.get("Retry-After") ?? 60));
  case "SCRAPING_UNAVAILABLE":
  case "SCRAPING_ERROR":
    return retryWithBackoff();
  default:
    // POST_AGE_RESTRICTED, POST_NOT_ACCESSIBLE, POST_NOT_FOUND: permanent
    return markChallengeUnreadable(error);
}