{"record":{"id":"50d0309b80895667","repo":"mastra-ai/mastra","slug":"version-number-input-versionnumber-already-exis-50d030","errorCode":null,"errorMessage":"Version number ${input.versionNumber} already exists for skill ${input.skillId}","messagePattern":"Version number (.+?) already exists for skill (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/storage/domains/skills/inmemory.ts","lineNumber":321,"sourceCode":"      perPage: perPageForResponse,\n      hasMore: offset + perPage < clonedConfigs.length,\n    };\n  }\n\n  // ==========================================================================\n  // Skill Version Methods\n  // ==========================================================================\n\n  async createVersion(input: CreateSkillVersionInput): Promise<SkillVersion> {\n    // Check if version with this ID already exists\n    if (this.db.skillVersions.has(input.id)) {\n      throw new Error(`Version with id ${input.id} already exists`);\n    }\n\n    // Check for duplicate (skillId, versionNumber) pair\n    for (const version of this.db.skillVersions.values()) {\n      if (version.skillId === input.skillId && version.versionNumber === input.versionNumber) {\n        throw new Error(`Version number ${input.versionNumber} already exists for skill ${input.skillId}`);\n      }\n    }\n\n    const version: SkillVersion = {\n      ...input,\n      createdAt: new Date(),\n    };\n\n    // Deep clone before storing\n    this.db.skillVersions.set(input.id, this.deepCopyVersion(version));\n    return this.deepCopyVersion(version);\n  }\n\n  async getVersion(id: string): Promise<SkillVersion | null> {\n    const version = this.db.skillVersions.get(id);\n    return version ? this.deepCopyVersion(version) : null;\n  }\n","sourceCodeStart":303,"sourceCodeEnd":339,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/storage/domains/skills/inmemory.ts#L303-L339","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait storage.createVersion({ id: genId(), skillId: 'my-skill', versionNumber: 1 });\n// after\nconst versions = await storage.listVersions('my-skill', { perPage: false });\nconst next = Math.max(0, ...versions.versions.map(v => v.versionNumber)) + 1;\nawait storage.createVersion({ id: genId(), skillId: 'my-skill', versionNumber: next });","handlingStrategy":"validation","validationCode":"async function nextVersionNumber(storage, skillId: string) {\n  const { versions } = await storage.listVersions(skillId, { perPage: false });\n  return Math.max(0, ...versions.map(v => v.versionNumber)) + 1;\n}","typeGuard":null,"tryCatchPattern":"try {\n  await storage.createVersion(input);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('already exists for skill')) {\n    input.versionNumber = await nextVersionNumber(storage, input.skillId);\n    return storage.createVersion(input);\n  }\n  throw err;\n}","preventionTips":["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."],"tags":["duplicate-key","versioning","storage"],"backgroundTag":"duplicate-version-number","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}