{"record":{"id":"e01f888a39e17228","repo":"Hmbown/CodeWhale","slug":"the-runtime-returned-a-cursor-beyond-its-provider-model","errorCode":null,"errorMessage":"The Runtime returned a cursor beyond its provider model catalog.","messagePattern":"The Runtime returned a cursor beyond its provider model catalog\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/runtime_web/app.mjs","lineNumber":699,"sourceCode":"    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    }\n    seenCursors.add(nextCursor);\n    cursor = nextCursor;\n  }\n  throw new Error(`The provider catalog exceeds ${MAX_PROVIDER_MODELS} models.`);\n}\n\nfunction startBrowserClient() {\n  const dom = {\n    shell: document.querySelector(\"#app-shell\"),\n    rail: document.querySelector(\"#thread-rail\"),\n    railOpen: document.querySelector(\"#rail-open\"),\n    railClose: document.querySelector(\"#rail-close\"),\n    railScrim: document.querySelector(\"#rail-scrim\"),\n    search: document.querySelector(\"#thread-search\"),\n    threadList: document.querySelector(\"#thread-list\"),\n    newThread: document.querySelector(\"#new-thread\"),\n    newThreadDialog: document.querySelector(\"#new-thread-dialog\"),","sourceCodeStart":681,"sourceCodeEnd":717,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/runtime_web/app.mjs#L681-L717","documentation":"Thrown when the Runtime returns another cursor even though the loader has already accumulated entries.length >= expectedTotal models. The catalog said it had N models; once N are collected there must be no further pages. Continuing would collect duplicates beyond the declared catalog.","triggerScenarios":"expectedTotal undercounts the real catalog size (or pages return duplicates), so after collecting `total` entries the Runtime still supplies a nextCursor.","commonSituations":"Provider added models between the first page (which fixed total) and later pages; a Runtime cursor implementation with an off-by-one that emits a trailing cursor; duplicate model ids inflating entries past the true count.","solutions":["Restart the load after the catalog settles so the first page's `total` is accurate","Check the Runtime cursor logic for an off-by-one that emits a cursor past the last page","Deduplicate provider model ids so entries.length tracks the true count","Update/restart the Runtime if it is an older build with a known cursor bug"],"exampleFix":"// before: appending pages while a cursor exists, ignoring total\nwhile (true) { const page = await fetchPage(cursor); entries.push(...page.models); if (!page.nextCursor) break; cursor = page.nextCursor; }\n// after: stop when the declared total is reached\nif (entries.length >= expectedTotal && page.nextCursor) throw new Error('cursor beyond catalog');","handlingStrategy":"validation","validationCode":"if (entries.length >= expectedTotal && page.nextCursor) throw new Error('cursor beyond catalog');","typeGuard":"const withinCatalog = (entries, total, page) => entries.length < total || !page?.nextCursor;","tryCatchPattern":"try { models = await loadCatalog(); } catch (e) { if (String(e.message).includes('beyond')) await reloadCatalog(); }","preventionTips":["Re-fetch `total` if the catalog may have grown mid-load","Deduplicate model ids so counts stay accurate","Fix off-by-one trailing cursors in the Runtime","Stop paginating once the declared total is reached"],"tags":["pagination","cursor","provider-catalog"],"backgroundTag":"invalid-state-transition","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"}