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
- 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).
- Check existing versions with listVersions(scorerDefinitionId) before choosing a versionNumber.
- Wrap createVersion in try-catch and retry with an incremented versionNumber on this error.
- 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
- Always derive the next versionNumber from the stored max, never hardcode it.
- Serialize writes for the same scorerDefinitionId to avoid version races.
- Make seed/import scripts idempotent by checking existing versions first.
- Catch and retry with an incremented versionNumber on this specific message.
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
- Scorer definition with id ${scorerDefinition.id} already exi
- Scorer definition with id ${id} not found
- Version with id ${input.id} already exists
- Agent with id ${agent.id} already exists
- Agent with id ${id} not found
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/4d5887c462d5cfe2.
Report an issue: GitHub.