openclaw/openclaw · error · CatalogParamsError

Codex session is not a non-archived interactive Codex sessio

Error message

Codex session is not a non-archived interactive Codex session

What it means

Thrown by requireCatalogEligibleThread when neither the cached (cadence-safe) page scan nor the forced-refresh scan located the requested thread id among non-archived interactive Codex sessions. Mutating actions (continue/archive/terminal) require an authoritative eligibility confirmation before proceeding.

Source

Thrown at extensions/codex/src/session-catalog-terminal.ts:91

    ? { canOpenTerminalCodex: true }
    : {};
}

export async function requireCatalogEligibleThread(
  control: CodexSessionCatalogControl,
  threadId: string,
): Promise<CodexSessionCatalogSession> {
  // Mutating actions use a fresh pinned control and authoritative thread/read. Passive positive hits
  // may use the cadence-safe page memo; only a miss must bypass it before rejecting a new thread.
  const cached = await findCatalogEligibleThread(control, threadId, false);
  if (cached) {
    return cached;
  }
  const refreshed = await findCatalogEligibleThread(control, threadId, true);
  if (refreshed) {
    return refreshed;
  }
  throw new CatalogParamsError("Codex session is not a non-archived interactive Codex session");
}

async function findCatalogEligibleThread(
  control: CodexSessionCatalogControl,
  threadId: string,
  forceRefresh: boolean,
): Promise<CodexSessionCatalogSession | undefined> {
  let cursor: string | undefined;
  const seenCursors = new Set<string>();
  for (let pageIndex = 0; pageIndex < MAX_ACTION_CATALOG_PAGES; pageIndex += 1) {
    const page = await control.listPage({
      limit: CODEX_SESSION_CATALOG_MAX_PAGE_LIMIT,
      ...(cursor ? { cursor } : {}),
      ...(forceRefresh ? { forceRefresh: true } : {}),
    });
    const candidate = page.sessions.find((session) => session.threadId === threadId);
    if (candidate) {
      if (isInteractiveThreadSource(candidate.source)) {

View on GitHub (pinned to 01804a7531)

Solutions

  1. Refresh the Codex session catalog and re-pick the threadId from a current page.
  2. Confirm the target is an interactive (non-archived) Codex session via `codex` CLI or app-server.
  3. If the session was archived, restore or re-create it before retrying.
Defensive patterns

Strategy: validation

Validate before calling

const fresh = await control.listPage({ limit: 100 });
const exists = fresh.sessions.some((s) => s.threadId === targetThreadId);
if (!exists) {
  // tell the user the session is gone and stop
}

Try / catch

try {
  await requireCatalogEligibleThread(control, threadId);
} catch (error) {
  if (error instanceof CatalogParamsError && /not a non-archived interactive/.test(error.message)) {
    // refresh catalog, reselect, or inform user the session is unavailable
  }
  throw error;
}

Prevention

When it happens

Trigger: Calling continue/archive/terminal resume with a threadId that does not exist on the app-server, is archived, belongs to a non-interactive source, or was deleted between catalog list and action.

Common situations: Stale threadId copied from an old catalog page; the session was archived by another client or CLI in the meantime; the thread is a non-interactive/internal Codex thread type.

Related errors


AI-assisted analysis of openclaw/openclaw@01804a7531 (2026-08-12). Data as JSON: /api/errors/60841fe32b3f5f36. Report an issue: GitHub.