mastra-ai/mastra · error · MastraError

OBSERVABILITY_MISSING_RECORD_ID

OBSERVABILITY_MISSING_RECORD_ID

Error message

Observability record is missing required id field '${String(idField)}'

What it means

upsertByIdField indexes observability records (metrics, logs, scores, feedback) by a required id field to maintain delta cursors. If the record's id field is null or undefined, this USER-category error is thrown because such a record cannot be inserted or tracked.

Source

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

    return cursorId;
  }

  /**
   * Upserts a record into an append-only collection keyed by an id field.
   *
   * If an existing record with the same id is found, it is replaced in place
   * (preserving its cursor id so delta polling does not re-emit it). Otherwise
   * the record is appended and a fresh cursor id is allocated.
   */
  private upsertByIdField<T extends Record<string, unknown>>(
    records: T[],
    cursorIds: Map<T, number>,
    record: T,
    idField: keyof T,
  ): void {
    const id = record[idField];
    if (id == null) {
      throw new MastraError({
        id: 'OBSERVABILITY_MISSING_RECORD_ID',
        domain: ErrorDomain.STORAGE,
        category: ErrorCategory.USER,
        text: `Observability record is missing required id field '${String(idField)}'`,
      });
    }
    const existingIndex = records.findIndex(existing => existing[idField] === id);
    if (existingIndex !== -1) {
      const previous = records[existingIndex]!;
      const cursorId = cursorIds.get(previous);
      cursorIds.delete(previous);
      records[existingIndex] = record;
      if (cursorId !== undefined) {
        cursorIds.set(record, cursorId);
      }
      return;
    }
    records.push(record);

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Ensure every record passed to the batch/create methods has its id field populated before calling.
  2. Add upstream validation at the producer/client boundary that rejects records lacking ids.
  3. Generate ids at creation time (crypto.randomUUID()) when records are synthesized in code.
  4. Check for field renames between serialization and insertion (e.g. mapping 'key' to 'id').

Example fix

// before
await storage.createScore({ value: 0.9 }); // no id -> throws

// after
await storage.createScore({ id: crypto.randomUUID(), value: 0.9 });
Defensive patterns

Strategy: validation

Validate before calling

function requireId<T extends Record<string, unknown>>(rec: T, idField: keyof T): void {
  if (rec[idField] == null) throw new Error(`Record missing required id field '${String(idField)}'`);
}
records.forEach(r => requireId(r, 'id'));
await storage.batchCreateFeedback(records);

Type guard

function hasId<T extends { id?: unknown }>(r: T): r is T & { id: string | number } {
  return r.id != null;
}

Try / catch

try {
  await storage.createScore(record);
} catch (e) {
  if ((e as MastraError).id === 'OBSERVABILITY_MISSING_RECORD_ID') {
    logger.error('Dropping record without id', record);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling batchCreateMetrics, batchCreateLogs, createScore, batchCreateScores, createFeedback, or batchCreateFeedback with a record whose id field (id/scoreId/feedbackId, etc.) is missing, null, or undefined.

Common situations: Deserializing records from JSON/CSV where the id column was dropped; constructing records programmatically and forgetting the id; a producer emitting telemetry events without ids; schema changes renaming the id field.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


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