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."
}error | HTTP | Retry? | Meaning |
|---|---|---|---|
POST_AGE_RESTRICTED | 422 | No | The post is age-gated. Only its author can fix this by reposting without the restriction |
POST_NOT_ACCESSIBLE | 422 | No | The post is private or otherwise not public |
POST_NOT_FOUND | 404 | No | The post no longer exists at that URL |
SCRAPING_RATE_LIMITED | 429 | Yes | Wait for the Retry-After header, then retry |
SCRAPING_UNAVAILABLE | 503 | Later | Scraping is temporarily down |
SCRAPING_ERROR | 502 | Yes | Scraping 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
POST …/comments/refreshPOST …/metrics/refreshPOST /admin/creators/{userId}/refresh(for profiles,404means the profile no longer exists)
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);
}