nexu-io/open-design · warning · Error
petshare list page ${page} failed: ${resp.status} ${resp.sta
Error message
petshare list page ${page} failed: ${resp.status} ${resp.statusText} What it means
Thrown by listPetSharePets when the HTTP GET to the PetShare catalog API (PETSHARE_BASE/api/pets?page=N&pageSize=24) returns a non-2xx status. The error message includes the page number and the HTTP status+statusText for diagnostics. This is a transient external-dependency failure — the Supabase-hosted PetShare function is unreachable or returning an error.
Source
Thrown at apps/daemon/src/community-pets-sync.ts:117
async function pathExists(p: string): Promise<boolean> {
try {
await stat(p);
return true;
} catch {
return false;
}
}
async function listPetSharePets(limit: number | null): Promise<PetTask[]> {
const tasks: PetTask[] = [];
let page = 1;
const pageSize = 24;
for (;;) {
const url = `${PETSHARE_BASE}/api/pets?page=${page}&pageSize=${pageSize}`;
const resp = await fetch(url);
if (!resp.ok) {
throw new Error(`petshare list page ${page} failed: ${resp.status} ${resp.statusText}`);
}
const data = (await resp.json()) as PetShareListResponse;
for (const pet of data.pets ?? []) {
const folder = sanitizeFolder(pet.id);
if (!folder) continue;
const spritesheetUrl = pet.spritesheetUrl?.startsWith('http')
? pet.spritesheetUrl
: `${PETSHARE_BASE}${pet.spritesheetUrl ?? ''}`;
const ext = extOf(pet.spritesheetPath ?? spritesheetUrl);
tasks.push({
source: 'petshare',
folder,
manifest: {
id: pet.id,
displayName: pet.displayName,
description: pet.description ?? '',
spritesheetPath: `spritesheet.${ext}`,
author: pet.ownerName,View on GitHub (pinned to 5be4028344)
Solutions
- Retry the sync after a short delay — PetShare outages are typically transient.
- Check if the PETSHARE_BASE Supabase project is active and the edge function is deployed.
- If rate-limited, reduce sync frequency or add backoff.
- Use source: 'hatchery' as a fallback if only PetShare is down.
Example fix
// before — single fetch with no retry
const resp = await fetch(url);
if (!resp.ok) throw new Error(`petshare list page ${page} failed: ${resp.status}`);
// after — retry with backoff
for (let attempt = 0; attempt < 3; attempt++) {
const resp = await fetch(url);
if (resp.ok) break;
if (attempt === 2 || resp.status < 500) {
throw new Error(`petshare list page ${page} failed: ${resp.status} ${resp.statusText}`);
}
await new Promise(r => setTimeout(r, 1000 * (attempt + 1)));
} Defensive patterns
Strategy: retry
Validate before calling
// Before syncing, probe PetShare availability with a lightweight HEAD request.
async function isPetShareReachable(): Promise<boolean> {
try {
const resp = await fetch(`${PETSHARE_BASE}/api/pets?page=1&pageSize=1`, {
method: 'HEAD',
signal: AbortSignal.timeout(5_000),
});
return resp.ok;
} catch {
return false;
}
} Type guard
export function isPetShareListError(error: unknown): boolean {
return error instanceof Error && /petshare list page \d+ failed/.test(error.message);
} Try / catch
try {
const tasks = await listPetSharePets(limit);
} catch (error) {
if (error instanceof Error && error.message.includes('petshare list page')) {
// Transient — surface as partial failure, try hatchery instead
syncResult.errors.push(error.message);
const hatcheryTasks = await listHatcheryPets(limit);
tasks.push(...hatcheryTasks);
} else throw error;
} Prevention
- Treat PetShare as a best-effort external dependency — always provide a fallback source.
- Retry with exponential backoff for 5xx responses.
- Surface partial failures in the sync result so the user knows which catalog failed.
- Cache the last successful sync to serve stale data during outages.
When it happens
Trigger: Calling the community pets sync (POST /api/codex-pets/sync with source 'petshare' or 'all') when the PetShare Supabase edge function returns 4xx/5xx. The fetch at line 115 gets a response, resp.ok is false, and the error is thrown at line 117.
Common situations: The PetShare Supabase function is rate-limited (429), under maintenance (503), or the function deployment is cold/timing out. A network proxy returns a 502. The PETSHARE_BASE URL has changed or the Supabase project is paused.
Related errors
- hatchery list failed: ${resp.status} ${resp.statusText}
- download ${url} failed: ${resp.status} ${resp.statusText}
- Could not fetch ${url} — the site may block server-side requ
- invalid brand asset url: ${String(url)}
- blocked non-public brand asset host: ${host}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/12bccffe93a6f8a6.
Report an issue: GitHub.