openclaw/openclaw · error · CatalogParamsError

Codex session catalog parameters must be an object

Error message

Codex session catalog parameters must be an object

What it means

Thrown as CatalogParamsError by readPageParams in session-catalog-parsing.ts:216 when the page-params value is not a record (object). Page params must be a plain object so its keys can be validated; arrays, strings, numbers, booleans, and null all fail the isRecord check.

Source

Thrown at extensions/codex/src/session-catalog-parsing.ts:216

  if (trimmed.length > maxLength) {
    throw new CatalogParamsError(`${key} must be at most ${maxLength} characters`);
  }
  return trimmed;
}

export function requireOnlyKeys(
  params: Record<string, unknown>,
  allowed: ReadonlySet<string>,
): void {
  const unknown = Object.keys(params).find((key) => !allowed.has(key));
  if (unknown) {
    throw new CatalogParamsError(`unknown Codex session catalog parameter: ${unknown}`);
  }
}

export function readPageParams(value: unknown): CodexSessionCatalogPageParams {
  if (!isRecord(value)) {
    throw new CatalogParamsError("Codex session catalog parameters must be an object");
  }
  const params = value;
  requireOnlyKeys(params, new Set(["cursor", "limit", "searchTerm", "cwd"]));
  const cursor = readBoundedOptionalString(params, "cursor", MAX_CURSOR_LENGTH);
  const searchTerm = readBoundedOptionalString(params, "searchTerm", MAX_SEARCH_LENGTH);
  const cwd = readBoundedOptionalString(params, "cwd", MAX_CWD_LENGTH);
  return {
    limit: normalizeLimit(params.limit, "limit"),
    ...(cursor ? { cursor } : {}),
    ...(searchTerm ? { searchTerm } : {}),
    ...(cwd ? { cwd } : {}),
  };
}

export function readGatewayParams(value: unknown): CodexSessionCatalogParams {
  if (value !== undefined && !isRecord(value)) {
    throw new CatalogParamsError("Codex session catalog parameters must be an object");
  }

View on GitHub (pinned to 01804a7531)

Solutions

  1. Always pass a plain object (at minimum {}) to readPageParams.
  2. If you have a bare cursor, wrap it: {cursor: cursorValue}.
  3. JSON.parse the payload before calling if it arrived as a string, and assert it is an object.
  4. Use readGatewayParams instead if you need undefined-to-default behaviour.

Example fix

// before
readPageParams(JSON.stringify({ cursor })); // throws
readPageParams(null); // throws

// after
readPageParams(typeof raw === 'string' ? JSON.parse(raw) : (raw ?? {}));
// or simply
readPageParams({ cursor });
Defensive patterns

Strategy: type-guard

Validate before calling

// Ensure page params is a plain object before calling readPageParams.
function asPageParams(value: unknown): Record<string, unknown> {
  return value && typeof value === 'object' && !Array.isArray(value)
    ? value as Record<string, unknown>
    : {};
}

readPageParams(asPageParams(raw));

Type guard

function isParamsObject(value: unknown): value is Record<string, unknown> {
  return typeof value === 'object' && value !== null && !Array.isArray(value);
}

Prevention

When it happens

Trigger: Passing page params as a JSON string (not yet parsed), an array of params, a single string cursor, null, or a number. Undefined would also fail here because readPageParams requires the value to be a record (no default-to-empty unlike readGatewayParams).

Common situations: Client forwards a JSON.parse'd array instead of an object; passes null explicitly; sends the cursor string directly instead of wrapping it in {cursor: ...}.

Related errors


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