{"record":{"id":"0d25fc84c1b742dc","repo":"Hmbown/CodeWhale","slug":"the-runtime-returned-an-invalid-provider-model-page","errorCode":null,"errorMessage":"The Runtime returned an invalid provider model page.","messagePattern":"The Runtime returned an invalid provider model page\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/runtime_web/app.mjs","lineNumber":674,"sourceCode":"  const entries = [];\n  const seenCursors = new Set();\n  let expectedTotal;\n  let cursor = \"\";\n  for (let page = 0; page < MAX_PROVIDER_MODEL_PAGES; page += 1) {\n    const query = new URLSearchParams({ limit: String(PROVIDER_MODELS_PAGE_SIZE) });\n    if (cursor) query.set(\"cursor\", cursor);\n    const response = await fetchPage(\n      `/v1/providers/${encodeURIComponent(provider)}/models?${query.toString()}`,\n    );\n    if (String(response?.provider || \"\") !== provider) {\n      throw new Error(\"The Runtime returned a model page for a different provider.\");\n    }\n    if (!Array.isArray(response?.models)\n      || response.models.length > PROVIDER_MODELS_PAGE_SIZE\n      || !Number.isSafeInteger(response.total)\n      || response.total < 0\n      || response.total > MAX_PROVIDER_MODELS) {\n      throw new Error(\"The Runtime returned an invalid provider model page.\");\n    }\n    if (expectedTotal !== undefined && expectedTotal !== response.total) {\n      throw new Error(\"The provider catalog changed; restart loading its models.\");\n    }\n    expectedTotal = response.total;\n    const pageEntries = response.models;\n    if (entries.length + pageEntries.length > MAX_PROVIDER_MODELS) {\n      throw new Error(`The provider catalog exceeds ${MAX_PROVIDER_MODELS} models.`);\n    }\n    entries.push(...pageEntries);\n\n    const nextCursor = typeof response?.nextCursor === \"string\"\n      ? response.nextCursor.trim()\n      : \"\";\n    if (!nextCursor) {\n      if (entries.length !== expectedTotal) {\n        throw new Error(\"The Runtime returned an incomplete provider model catalog.\");\n      }","sourceCodeStart":656,"sourceCodeEnd":692,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/runtime_web/app.mjs#L656-L692","documentation":"This error is thrown by the browser client's provider model pagination loader (collectProviderModelPages) when a page response from the Runtime fails shape validation: models must be an array of at most PROVIDER_MODELS_PAGE_SIZE entries, and total must be a safe non-negative integer no larger than MAX_PROVIDER_MODELS. It exists so a misbehaving Runtime cannot feed the UI malformed catalog data.","triggerScenarios":"A call to the Runtime's provider models endpoint returns a response whose `models` is not an array, contains more than PROVIDER_MODELS_PAGE_SIZE entries, whose `total` is missing, non-numeric, non-safe-integer, negative, or exceeds MAX_PROVIDER_MODELS.","commonSituations":"A Runtime built from an older/newer revision returning a different page payload shape; a proxy or dev server returning an HTML error page; a hand-edited or mocked Runtime response; a Runtime bug emitting a bad total after catalog churn.","solutions":["Restart the Runtime (`codewhale web`) so browser and Runtime versions match","Inspect the raw response of the provider models endpoint and confirm it returns {models:[], total:<safe int>}","Check for a reverse proxy or service worker serving a stale/corrupt response for /v1 endpoints","Verify the runtime web bundle (app.mjs) and Runtime backend are from the same build"],"exampleFix":"// before: passing raw API output straight into UI logic\nconst models = await api(path);\nrender(models.models);\n// after: validating the page shape before rendering\nif (Array.isArray(page?.models) && Number.isSafeInteger(page?.total)) render(page.models);\nelse throw new Error('invalid provider model page');","handlingStrategy":"validation","validationCode":"function isValidModelPage(page, pageSize) {\n  return Array.isArray(page?.models) && page.models.length <= pageSize\n    && Number.isSafeInteger(page?.total) && page.total >= 0;\n}","typeGuard":"const isModelPage = (r) => Array.isArray(r?.models) && Number.isSafeInteger(r?.total) && r.total >= 0;","tryCatchPattern":"try { const page = await api(path); if (!isModelPage(page)) throw new Error('invalid provider model page'); } catch (e) { console.error('model page rejected:', e.message); }","preventionTips":["Pin Runtime and browser bundle to the same build/version","Never mock /v1 endpoints with hand-shaped payloads differing from the real schema","Check proxied responses are still application/json","Watch for provider catalogs whose totals can exceed client caps"],"tags":["pagination","provider-catalog","validation"],"backgroundTag":"unexpected-response-shape","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}