mastra-ai/mastra · warning · MastraError

OBSERVABILITY_INVALID_DELTA_CURSOR

OBSERVABILITY_INVALID_DELTA_CURSOR

Error message

Invalid observability delta cursor

What it means

decodeDeltaCursor validates the string form of an observability delta cursor: it must be all digits. A cursor failing the /^\d+$/ regex (empty string, letters, base64 blob, negative sign) indicates corruption or a cursor produced by a different mechanism, so this USER-category error is thrown.

Source

Thrown at packages/core/src/storage/domains/observability/inmemory.ts:223

      const cursorId = cursorIds.get(previous);
      cursorIds.delete(previous);
      records[existingIndex] = record;
      if (cursorId !== undefined) {
        cursorIds.set(record, cursorId);
      }
      return;
    }
    records.push(record);
    cursorIds.set(record, this.allocateObservabilityCursorId());
  }

  private encodeDeltaCursor(cursorId?: number | null): string {
    return (cursorId ?? 0).toString();
  }

  private decodeDeltaCursor(cursor: string): number {
    if (!/^\d+$/.test(cursor)) {
      throw new MastraError({
        id: 'OBSERVABILITY_INVALID_DELTA_CURSOR',
        domain: ErrorDomain.MASTRA_OBSERVABILITY,
        category: ErrorCategory.USER,
        text: 'Invalid observability delta cursor',
      });
    }

    const cursorId = Number.parseInt(cursor, 10);
    if (!Number.isInteger(cursorId) || cursorId < 0) {
      throw new MastraError({
        id: 'OBSERVABILITY_INVALID_DELTA_CURSOR',
        domain: ErrorDomain.MASTRA_OBSERVABILITY,
        category: ErrorCategory.USER,
        text: 'Invalid observability delta cursor',
      });
    }

    return cursorId;

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Only pass cursors obtained from a previous response of the same storage instance; never hand-construct them.
  2. Reset the poller's cursor (start from the beginning / undefined cursor) when an invalid cursor is detected.
  3. Validate cursor format before sending if cursors cross process/serialization boundaries (e.g. base64-encoded payloads).
  4. Clear stale cursor state in your job/store if the backend was switched or the format changed.

Example fix

// before
const page = await storage.listMetrics({ cursor: lastCursor ?? 'abc' }); // throws

// after
const page = await storage.listMetrics({ cursor: isValidNumericCursor(lastCursor) ? lastCursor : undefined });
Defensive patterns

Strategy: validation

Validate before calling

const isValidDeltaCursor = (c: unknown): c is string => typeof c === 'string' && /^\d+$/.test(c);
if (cursor !== undefined && !isValidDeltaCursor(cursor)) cursor = undefined; // restart from beginning

Type guard

function isValidDeltaCursor(c: unknown): c is string {
  return typeof c === 'string' && /^\d+$/.test(c);
}

Try / catch

try {
  page = await storage.listLogs({ cursor });
} catch (e) {
  if ((e as MastraError).id === 'OBSERVABILITY_INVALID_DELTA_CURSOR') {
    cursor = undefined;
    page = await storage.listLogs({}); // reset cursor, restart polling
  } else throw e;
}

Prevention

When it happens

Trigger: Calling afterCursorId (directly or via a delta-polling list method) with a malformed cursor string — empty, non-numeric, truncated, or from another storage backend's cursor format.

Common situations: Persisting cursors to a store/file and mangling them; passing a cursor from a different provider (DB cursors are not numeric strings); hand-crafting cursors in tests or scripts; stale clients after a cursor format change.

Related errors


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