{"record":{"id":"60accf68f2e8c22a","repo":"Hmbown/CodeWhale","slug":"the-provider-catalog-exceeds-max-provider-models-models","errorCode":null,"errorMessage":"The provider catalog exceeds ${MAX_PROVIDER_MODELS} models.","messagePattern":"The provider catalog exceeds (.+?) models\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/runtime_web/app.mjs","lineNumber":682,"sourceCode":"      `/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      }\n      return entries;\n    }\n    if (pageEntries.length === 0 || seenCursors.has(nextCursor)) {\n      throw new Error(\"The Runtime returned a non-progressing model cursor.\");\n    }\n    if (entries.length >= expectedTotal) {\n      throw new Error(\"The Runtime returned a cursor beyond its provider model catalog.\");\n    }","sourceCodeStart":664,"sourceCodeEnd":700,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/runtime_web/app.mjs#L664-L700","documentation":"Thrown when appending a fetched page would push the accumulated model entries past MAX_PROVIDER_MODELS, the hard cap on catalog size. It prevents unbounded memory growth in the browser if a provider reports an enormous or runaway catalog.","triggerScenarios":"entries.length + pageEntries.length > MAX_PROVIDER_MODELS during pagination — the provider's catalog is larger than the cap, or a cursor loop is fetching more entries than `total` promised.","commonSituations":"A provider exposing tens of thousands of models; a Runtime cursor bug returning overlapping pages so entries accumulate past total; a misconfigured provider config listing a non-paginated mega-catalog.","solutions":["Reduce the number of models the provider exposes or filter the provider's model list in configuration","Restart loading after fixing any Runtime cursor bug (overlapping pages)","Check the Runtime for duplicate entries across pages that inflate entries.length","Raise MAX_PROVIDER_MODELS only if a legitimately huge catalog must be supported"],"exampleFix":"// before: fetching all pages unconditionally\nconst models = await collectProviderModelPages(provider.id, fetchPage);\n// after: pre-filter the provider or paginate from a filtered query\nconst models = await collectProviderModelPages(provider.id, (p) => fetchPage(p + '?search=' + query));","handlingStrategy":"validation","validationCode":"if (provider.modelCount > MAX_PROVIDER_MODELS) warn('provider catalog exceeds client cap before loading');","typeGuard":"const fitsCap = (n, cap) => Number.isSafeInteger(n) && n >= 0 && n <= cap;","tryCatchPattern":"try { models = await collectProviderModelPages(id, fetch); } catch (e) { if (String(e.message).includes('exceeds')) offerFilteredSearch(); }","preventionTips":["Cap provider model lists in configuration","Search/filter models instead of loading whole catalogs","Monitor catalogs that grow near the cap","Deduplicate models server-side so pages do not inflate counts"],"tags":["pagination","limit-exceeded","provider-catalog"],"backgroundTag":"value-out-of-range","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"}