mastra-ai/mastra · error

Version number ${input.versionNumber} already exists for sco

Error message

Version number ${input.versionNumber} already exists for scorer definition ${input.scorerDefinitionId}

What it means

This error is thrown by the in-memory scorer-definitions storage when creating a new scorer definition version whose (scorerDefinitionId, versionNumber) pair already exists. The library enforces unique, monotonically meaningful version numbers per scorer definition, so re-inserting the same version number for the same definition is rejected to protect version history integrity.

Source

Thrown at packages/core/src/storage/domains/scorer-definitions/inmemory.ts:214

      perPage: perPageForResponse,
      hasMore: offset + perPage < clonedScorers.length,
    };
  }

  // ==========================================================================
  // Scorer Definition Version Methods
  // ==========================================================================

  async createVersion(input: CreateScorerDefinitionVersionInput): Promise<ScorerDefinitionVersion> {
    // Check if version with this ID already exists
    if (this.db.scorerDefinitionVersions.has(input.id)) {
      throw new Error(`Version with id ${input.id} already exists`);
    }

    // Check for duplicate (scorerDefinitionId, versionNumber) pair
    for (const version of this.db.scorerDefinitionVersions.values()) {
      if (version.scorerDefinitionId === input.scorerDefinitionId && version.versionNumber === input.versionNumber) {
        throw new Error(
          `Version number ${input.versionNumber} already exists for scorer definition ${input.scorerDefinitionId}`,
        );
      }
    }

    const version: ScorerDefinitionVersion = {
      ...input,
      createdAt: new Date(),
    };

    // Deep clone before storing
    this.db.scorerDefinitionVersions.set(input.id, this.deepCopyVersion(version));
    return this.deepCopyVersion(version);
  }

  async getVersion(id: string): Promise<ScorerDefinitionVersion | null> {
    const version = this.db.scorerDefinitionVersions.get(id);
    return version ? this.deepCopyVersion(version) : null;

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Pass input.versionNumber explicitly as one more than the max existing versionNumber for that scorerDefinitionId (or omit it if the API computes the next number automatically).
  2. Check existing versions with listVersions(scorerDefinitionId) before choosing a versionNumber.
  3. Wrap createVersion in try-catch and retry with an incremented versionNumber on this error.
  4. Serialize concurrent version creation for the same definition (single-writer or lock) to avoid races.

Example fix

// before
await storage.createVersion({ id: v2, scorerDefinitionId: 'scorer-1', versionNumber: 2, ... });
await storage.createVersion({ id: v3, scorerDefinitionId: 'scorer-1', versionNumber: 2, ... }); // throws
// after
const { versions } = await storage.listVersions('scorer-1', {}, 0, false);
const next = Math.max(...versions.map(v => v.versionNumber)) + 1;
await storage.createVersion({ id: v3, scorerDefinitionId: 'scorer-1', versionNumber: next, ... });
Defensive patterns

Strategy: validation

Validate before calling

const { versions } = await storage.listVersions(scorerDefinitionId, {}, 0, false);
if (versions.some(v => v.versionNumber === input.versionNumber)) {
  throw new Error(`versionNumber ${input.versionNumber} already used`);
}

Type guard

function isVersionAvailable(versions: { versionNumber: number }[], versionNumber: number): boolean {
  return !versions.some(v => v.versionNumber === versionNumber);
}

Try / catch

try {
  await storage.createVersion(input);
} catch (e) {
  if (e instanceof Error && e.message.includes('already exists for scorer definition')) {
    await storage.createVersion({ ...input, versionNumber: input.versionNumber + 1 });
  } else throw e;
}

Prevention

When it happens

Trigger: Calling createVersion (via create) with an input.versionNumber that a prior version of the same scorerDefinitionId already used; e.g. manually passing versionNumber: 2 when versions 1 and 2 already exist, or retrying a failed request without generating a fresh version number.

Common situations: Importing scorer definitions twice from a seed script; concurrent writers both computing 'next version' before either commits; migration scripts that copy versions without renumbering.

Related errors


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