Hmbown/CodeWhale · error

The Runtime returned a non-progressing model cursor.

Error message

The Runtime returned a non-progressing model cursor.

What it means

Thrown when a page yields an empty entries array while still returning a cursor, or when the returned cursor was already visited. Pagination must strictly progress; either condition means an infinite loop would occur, so the loader aborts.

Solutions

  1. Restart `codewhale web` with a current Runtime build (fixed cursor logic)
  2. Bypass intermediate caches so each cursor request reaches the Runtime
  3. Verify the provider adapter honors the cursor/offset parameter
  4. Reload the dialog to restart pagination; if it recurs, file a Runtime bug with the cursor values

Example fix

// before: looping on the same cursor until the cap trips
while (nextCursor) { page = await fetch('?cursor=' + nextCursor); }
// after: detect non-progress like the loader does
if (!page.models.length || visited.has(page.nextCursor)) throw new Error('non-progressing model cursor');
Defensive patterns

Strategy: validation

Validate before calling

const visited = new Set(); if (visited.has(page.nextCursor) || !page.models.length) abortLoad();

Type guard

const cursorProgresses = (page, seen) => Array.isArray(page?.models) && page.models.length > 0 && !seen.has(page?.nextCursor);

Try / catch

try { models = await loadCatalog(); } catch (e) { if (String(e.message).includes('non-progressing')) reportRuntimeBug(e); }

Prevention

When it happens

Trigger: Runtime returns {models: [], nextCursor: "x"} or re-issues a cursor previously passed in seenCursors — typically a cursor implementation that doesn't advance (e.g. cursor encoding the same offset repeatedly).

Common situations: A Runtime build with a broken cursor codec; a provider adapter that ignores the cursor parameter and always returns the same page; caching middleware replaying an identical response for successive cursor requests.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/ef57bf60389092f2. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/runtime_web/app.mjs:696

    }
    expectedTotal = response.total;
    const pageEntries = response.models;
    if (entries.length + pageEntries.length > MAX_PROVIDER_MODELS) {
      throw new Error(`The provider catalog exceeds ${MAX_PROVIDER_MODELS} models.`);
    }
    entries.push(...pageEntries);

    const nextCursor = typeof response?.nextCursor === "string"
      ? response.nextCursor.trim()
      : "";
    if (!nextCursor) {
      if (entries.length !== expectedTotal) {
        throw new Error("The Runtime returned an incomplete provider model catalog.");
      }
      return entries;
    }
    if (pageEntries.length === 0 || seenCursors.has(nextCursor)) {
      throw new Error("The Runtime returned a non-progressing model cursor.");
    }
    if (entries.length >= expectedTotal) {
      throw new Error("The Runtime returned a cursor beyond its provider model catalog.");
    }
    seenCursors.add(nextCursor);
    cursor = nextCursor;
  }
  throw new Error(`The provider catalog exceeds ${MAX_PROVIDER_MODELS} models.`);
}

function startBrowserClient() {
  const dom = {
    shell: document.querySelector("#app-shell"),
    rail: document.querySelector("#thread-rail"),
    railOpen: document.querySelector("#rail-open"),
    railClose: document.querySelector("#rail-close"),
    railScrim: document.querySelector("#rail-scrim"),
    search: document.querySelector("#thread-search"),

View on GitHub (pinned to 73e0f67d83)