mastra-ai/mastra · error

GitHub cursor must be a positive page number.

Error message

GitHub cursor must be a positive page number.

What it means

parsePositiveCursor converts a pagination cursor string into a page number, defaulting to page 1 when no cursor is given. A cursor that is present but not a valid positive integer (e.g. '0', '-2', 'abc') is rejected — cursors for this API are plain page numbers.

Source

Thrown at mastracode/factory/src/integrations/github/integration.ts:1502

function getSingleSourceId(sourceIds: string[], message: string): string {
  if (sourceIds.length !== 1) throw new Error(message);
  return sourceIds[0]!;
}

function normalizeLabels(labels: string[] | undefined): string[] {
  return [...new Set((labels ?? []).map(label => label.trim()).filter(Boolean))];
}

function requireSourceId(sourceId: string | undefined, message: string): string {
  if (!sourceId) throw new Error(message);
  return sourceId;
}

function parsePositiveCursor(cursor: string | undefined): number {
  if (cursor === undefined) return 1;
  const page = parsePositiveInteger(cursor);
  if (page === null) throw new Error('GitHub cursor must be a positive page number.');
  return page;
}

function parsePositiveInteger(value: string): number | null {
  if (!/^\d+$/.test(value)) return null;
  const parsed = Number(value);
  return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : null;
}

function isNotFoundError(error: unknown): boolean {
  return typeof error === 'object' && error !== null && 'status' in error && error.status === 404;
}

/** Split an `owner/name` full name into its parts, or `null` when malformed. */
function splitRepoFullName(repoFullName: string): { owner: string; repo: string } | null {
  const slash = repoFullName.indexOf('/');
  if (slash <= 0 || slash === repoFullName.length - 1) return null;
  return { owner: repoFullName.slice(0, slash), repo: repoFullName.slice(slash + 1) };

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Pass the numeric page string this library returned (e.g. '2'), or omit the cursor for the first page.
  2. Do not feed opaque cursors from other APIs into GitHub pagination.
  3. Validate the cursor is a positive integer before passing.
  4. Clear stale stored cursors and restart pagination from the beginning.

Example fix

// before
list({ cursor: opaqueTokenFromOtherApi });
// after
list({ cursor: String(pageNumber) }); // e.g. '2'; omit for first page
Defensive patterns

Strategy: validation

Validate before calling

if (cursor !== undefined && !/^\d+$/.test(cursor)) throw new Error(`invalid page cursor: ${cursor}`);

Type guard

function isPageCursor(v: unknown): v is string {
  return v === undefined || (typeof v === 'string' && /^\d+$/.test(v) && Number(v) > 0);
}

Try / catch

try {
  return await list({ cursor });
} catch (e) {
  if ((e as Error).message.includes('cursor')) {
    log.warn('bad cursor, restarting from page 1', { cursor });
    return await list({});
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing a next-page cursor from a different API (opaque token) into this GitHub pagination; manually constructing '0'; corrupted stored cursor value.

Common situations: Mixing cursor formats between integrations (opaque base64 cursors vs numeric pages); persisting a cursor and loading a truncated/garbage value; hardcoding page 0.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/99196a533a42dcf8. Report an issue: GitHub.