Stirling-Tools/Stirling-PDF · warning · Error
Failed to download avatar: ${response.status} ${response.sta
Error message
Failed to download avatar: ${response.status} ${response.statusText} What it means
Thrown by downloadAndOptimizeAvatar() when fetch() to the OAuth provider's avatar URL returns a non-OK HTTP status. The error message includes the status code and status text for diagnosis. The fetch uses mode:'cors' and credentials:'omit' to comply with provider CORS policies. The caller syncOAuthAvatar() catches all errors and returns false, so this degrades gracefully to the user's existing picture or initials.
Source
Thrown at frontend/editor/src/saas/services/avatarSyncService.ts:73
}
}
/**
* Download and optimize an avatar image
* Resizes to 256x256 and converts to PNG format
* @param url Avatar URL from OAuth provider
* @returns Optimized image blob
*/
export async function downloadAndOptimizeAvatar(url: string): Promise<Blob> {
try {
// 1. Fetch image from provider URL
const response = await fetch(url, {
mode: "cors",
credentials: "omit",
});
if (!response.ok) {
throw new Error(
`Failed to download avatar: ${response.status} ${response.statusText}`,
);
}
const blob = await response.blob();
// 2. Create image bitmap
const img = await createImageBitmap(blob);
// 3. Create canvas and draw scaled image
const canvas = document.createElement("canvas");
canvas.width = AVATAR_SIZE;
canvas.height = AVATAR_SIZE;
const ctx = canvas.getContext("2d");
if (!ctx) {
throw new Error("Failed to get canvas context");
}View on GitHub (pinned to 9ef20dcab8)
Solutions
- Check the specific HTTP status code in the error message (403, 404, 429, 5xx)
- For expired URLs, re-authenticate via OAuth to get a fresh avatar URL in user_metadata
- Add retry with exponential backoff for 429 and 5xx status codes
- Fall back to the existing stored avatar or user initials (syncOAuthAvatar already does this)
Example fix
// before
if (!response.ok) {
throw new Error(`Failed to download avatar: ${response.status} ${response.statusText}`);
}
// after
if (!response.ok) {
if (response.status === 429 || response.status >= 500) {
await new Promise((r) => setTimeout(r, 1000));
return downloadAndOptimizeAvatar(url); // retry once
}
throw new Error(`Failed to download avatar: ${response.status} ${response.statusText}`);
} Defensive patterns
Strategy: fallback
Validate before calling
// Validate the avatar URL is reachable before full processing
// (syncOAuthAvatar already catches and degrades gracefully)
const url = getProviderAvatarUrl(user);
if (!url || !url.startsWith('https://')) {
return false; // skip sync, use existing avatar
} Try / catch
// syncOAuthAvatar already wraps in try/catch and returns false on failure:
// The caller should not throw — just check the boolean result:
const synced = await syncOAuthAvatar(user);
if (!synced) {
// Gracefully degrade to existing avatar or initials — no error UI needed
} Prevention
- Re-authenticate via OAuth periodically to get fresh avatar URLs before they expire
- Add retry with backoff for transient 429/5xx from provider CDNs
- Cache the optimized avatar blob locally so expired source URLs don't cause repeated failures
- Treat avatar sync as best-effort — never block user flows on its success
When it happens
Trigger: The avatar URL from OAuth provider metadata has expired or changed (GitHub avatar CDN URLs can rotate); the provider rate-limits unauthenticated image fetches (HTTP 429); the URL returns 403/404; CORS policy on the provider's CDN blocks the cross-origin request.
Common situations: Stale avatar URL cached in Supabase user_metadata after the provider rotated CDN links; GitHub/Google avatar CDN under rate limiting; provider image endpoint temporarily down; network proxy/firewall blocking the provider's image domain.
Related errors
- Sign up failed
- Failed to get canvas context
- OCR service error: ${title}
- Response is not a valid PDF. Header: "${head}"
- Google Drive is not configured
AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13).
Data as JSON: /api/errors/3d71684bfaf6b026.
Report an issue: GitHub.