{"record":{"id":"7a66c1f9c97b25db","repo":"nexu-io/open-design","slug":"hatchery-list-failed-resp-status-resp-status","errorCode":null,"errorMessage":"hatchery list failed: ${resp.status} ${resp.statusText}","messagePattern":"hatchery list failed: (.+?) (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"apps/daemon/src/community-pets-sync.ts","lineNumber":154,"sourceCode":"          tags: pet.tags ?? [],\n          source: 'codex-pet-share',\n          sourceUrl: `https://codex-pet-share.pages.dev/#/pets/${encodeURIComponent(pet.id ?? '')}`,\n        },\n        spritesheetUrl,\n        spritesheetExt: ext,\n      });\n      if (limit && tasks.length >= limit) return tasks;\n    }\n    if (page >= (data.totalPages ?? 1)) break;\n    page++;\n  }\n  return tasks;\n}\n\nasync function listHatcheryPets(limit: number | null): Promise<PetTask[]> {\n  const resp = await fetch(HATCHERY_LIST);\n  if (!resp.ok) {\n    throw new Error(`hatchery list failed: ${resp.status} ${resp.statusText}`);\n  }\n  const data = (await resp.json()) as HatcheryListResponse;\n  const tasks: PetTask[] = [];\n  for (const pet of data.pets ?? []) {\n    const folder = sanitizeFolder(pet.petManifestId || pet.id);\n    if (!folder) continue;\n    if (!pet.spritesheetUrl) continue;\n    tasks.push({\n      source: 'hatchery',\n      folder,\n      manifest: {\n        id: pet.petManifestId || pet.id,\n        displayName: pet.displayName,\n        description: pet.description ?? '',\n        spritesheetPath: 'spritesheet.webp',\n        author: pet.authorLabel,\n        authorXUrl: pet.authorXUrl,\n        source: 'j20-hatchery',","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/community-pets-sync.ts#L136-L172","documentation":"Thrown by listHatcheryPets when the HTTP GET to the Hatchery catalog API (HATCHERY_LIST at https://j20.nz/hatchery/api/pets.json) returns a non-2xx status. Unlike PetShare, the Hatchery API is a single flat JSON endpoint with no pagination. The error message includes the HTTP status and statusText for diagnostics.","triggerScenarios":"Calling the community pets sync (POST /api/codex-pets/sync with source 'hatchery' or 'all') when the j20.nz hatchery endpoint returns 4xx/5xx. The fetch at line 152 gets a response, resp.ok is false, and the error is thrown at line 154.","commonSituations":"The j20.nz server is down, the /hatchery/api/pets.json route has changed, or a CDN/proxy returns an error. Network connectivity to j20.nz is blocked or timing out.","solutions":["Retry the sync after a short delay — Hatchery outages are typically transient.","Verify https://j20.nz/hatchery/api/pets.json is accessible from the daemon's network.","Use source: 'petshare' as a fallback if only Hatchery is down.","If the endpoint has permanently moved, update HATCHERY_LIST constant."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Before syncing, probe Hatchery availability.\nasync function isHatcheryReachable(): Promise<boolean> {\n  try {\n    const resp = await fetch(HATCHERY_LIST, {\n      method: 'HEAD',\n      signal: AbortSignal.timeout(5_000),\n    });\n    return resp.ok;\n  } catch {\n    return false;\n  }\n}","typeGuard":"export function isHatcheryListError(error: unknown): boolean {\n  return error instanceof Error && error.message.startsWith('hatchery list failed');\n}","tryCatchPattern":"try {\n  const tasks = await listHatcheryPets(limit);\n} catch (error) {\n  if (error instanceof Error && error.message.startsWith('hatchery list failed')) {\n    // Transient — surface as partial failure, try petshare instead\n    syncResult.errors.push(error.message);\n    const petshareTasks = await listPetSharePets(limit);\n    tasks.push(...petshareTasks);\n  } else throw error;\n}","preventionTips":["Treat Hatchery as a best-effort external dependency.","Retry with exponential backoff for 5xx responses.","Surface partial failures in the sync result.","Fall back to PetShare when Hatchery is unavailable."],"tags":["network","external-api","community-pets","transient"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}