mastra-ai/mastra · error
Version number ${input.versionNumber} already exists for ski
Error message
Version number ${input.versionNumber} already exists for skill ${input.skillId} What it means
`createVersion` enforces that the `(skillId, versionNumber)` pair is unique: iterating existing versions, it throws if another version of the same skill already uses `input.versionNumber`. A skill cannot have two records with the same version number.
Source
Thrown at packages/core/src/storage/domains/skills/inmemory.ts:321
perPage: perPageForResponse,
hasMore: offset + perPage < clonedConfigs.length,
};
}
// ==========================================================================
// Skill Version Methods
// ==========================================================================
async createVersion(input: CreateSkillVersionInput): Promise<SkillVersion> {
// Check if version with this ID already exists
if (this.db.skillVersions.has(input.id)) {
throw new Error(`Version with id ${input.id} already exists`);
}
// Check for duplicate (skillId, versionNumber) pair
for (const version of this.db.skillVersions.values()) {
if (version.skillId === input.skillId && version.versionNumber === input.versionNumber) {
throw new Error(`Version number ${input.versionNumber} already exists for skill ${input.skillId}`);
}
}
const version: SkillVersion = {
...input,
createdAt: new Date(),
};
// Deep clone before storing
this.db.skillVersions.set(input.id, this.deepCopyVersion(version));
return this.deepCopyVersion(version);
}
async getVersion(id: string): Promise<SkillVersion | null> {
const version = this.db.skillVersions.get(id);
return version ? this.deepCopyVersion(version) : null;
}
View on GitHub (pinned to 75dd419e61)
Solutions
- Increment `versionNumber` for the skill before creating a new version (query existing versions and take max + 1).
- Fetch the skill's versions first and skip creation if the number already exists.
- Catch the error and treat as idempotent when the stored version content is identical.
- Serialize publishes (lock/queue) so concurrent jobs can't claim the same version number.
Example fix
// before
await storage.createVersion({ id: genId(), skillId: 'my-skill', versionNumber: 1 });
// after
const versions = await storage.listVersions('my-skill', { perPage: false });
const next = Math.max(0, ...versions.versions.map(v => v.versionNumber)) + 1;
await storage.createVersion({ id: genId(), skillId: 'my-skill', versionNumber: next }); Defensive patterns
Strategy: validation
Validate before calling
async function nextVersionNumber(storage, skillId: string) {
const { versions } = await storage.listVersions(skillId, { perPage: false });
return Math.max(0, ...versions.map(v => v.versionNumber)) + 1;
} Try / catch
try {
await storage.createVersion(input);
} catch (err) {
if (err instanceof Error && err.message.includes('already exists for skill')) {
input.versionNumber = await nextVersionNumber(storage, input.skillId);
return storage.createVersion(input);
}
throw err;
} Prevention
- Always compute the next version number from existing versions rather than hard-coding it.
- Bump version numbers on every republish.
- Lock or queue publishes so concurrent CI jobs can't race for the same number.
When it happens
Trigger: Calling `createVersion({ ..., skillId: 'x', versionNumber: 2 })` when skill `x` already has a version numbered 2, including via the `create`/`update` wrappers that call `createVersion` internally.
Common situations: Re-publishing a skill without bumping its version number, importing/exporting skill definitions across environments where version numbers collide, or parallel CI jobs publishing the same version concurrently.
Related errors
- Version with id ${input.id} already exists
- Version with id ${input.id} already exists
- Version number ${input.versionNumber} already exists for wor
- ${this.name}: version with id ${input.id} already exists
- DATASET_ITEM_NOT_FOUND
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/50d0309b80895667.
Report an issue: GitHub.