mastra-ai/mastra · error

${this.name}: version with id ${input.id} already exists

Error message

${this.name}: version with id ${input.id} already exists

What it means

createVersion ensures git history is initialized, then rejects a version whose id is already present in the versions map. Version records are immutable history entries, so duplicates are treated as a programming/data error rather than an idempotent re-write.

Source

Thrown at packages/core/src/storage/filesystem-versioned.ts:604

    const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);

    return {
      [listKey]: entities.slice(offset, offset + perPage),
      total: entities.length,
      page,
      perPage: perPageForResponse,
      hasMore: offset + perPage < entities.length,
    };
  }

  // ==========================================================================
  // Version Methods (in-memory + git history)
  // ==========================================================================

  async createVersion(input: TVersion): Promise<TVersion> {
    await this.ensureGitHistory();
    if (this.versions.has(input.id)) {
      throw new Error(`${this.name}: version with id ${input.id} already exists`);
    }

    const parentId = (input as Record<string, unknown>)[this.parentIdField] as string;

    // Check for duplicate (parentId, versionNumber) pair
    for (const v of this.versions.values()) {
      if ((v as Record<string, unknown>)[this.parentIdField] === parentId && v.versionNumber === input.versionNumber) {
        throw new Error(`${this.name}: version number ${input.versionNumber} already exists for entity ${parentId}`);
      }
    }

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

    this.versions.set(input.id, structuredClone(version));
    return structuredClone(version);

View on GitHub (pinned to 75dd419e61)

Solutions

  1. List existing versions and skip creation when the id is already present.
  2. Generate a unique version id (e.g. uuid) instead of deriving it deterministically.
  3. Catch the error and treat it as success if your flow is intentionally idempotent.

Example fix

// before
await store.createVersion({ id: `${entityId}-v${n}`, ... });
// after
const existing = await store.listVersions({ [parentIdField]: entityId });
if (!existing.versions.some(v => v.id === `${entityId}-v${n}`)) {
  await store.createVersion({ id: `${entityId}-v${n}`, ... });
}
Defensive patterns

Strategy: try-catch

Validate before calling

const versions = await store.listVersions({ [parentIdField]: entityId });
if (versions.versions.some(v => v.id === newVersion.id)) return; // already imported

Try / catch

try {
  await store.createVersion(version);
} catch (e) {
  if (String(e.message).includes('already exists')) return; // idempotent skip
  throw e;
}

Prevention

When it happens

Trigger: Calling createVersion with a TVersion whose id already exists in the store; replaying an event/import that contains an already-persisted version record.

Common situations: Re-running an import/migration script; id generated from entity id + versionNumber colliding after a retry; two workers creating the same version concurrently.

Related errors


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