mastra-ai/mastra · error

Version with id ${input.id} already exists

Error message

Version with id ${input.id} already exists

What it means

createVersion() rejects a new version whose id already exists in the version table. Version ids are primary keys; inserting a duplicate would overwrite or corrupt version history, so the domain throws eagerly.

Source

Thrown at packages/core/src/storage/domains/workspaces/inmemory.ts:252

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

    return {
      workspaces: clonedConfigs.slice(offset, offset + perPage),
      total: clonedConfigs.length,
      page,
      perPage: perPageForResponse,
      hasMore: offset + perPage < clonedConfigs.length,
    };
  }

  // ==========================================================================
  // Workspace Version Methods
  // ==========================================================================

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

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

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

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

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Generate a fresh unique id per version (crypto.randomUUID()) instead of reusing one
  2. Check existence first: if the version id already exists, skip or fetch the existing version instead of inserting
  3. Make createVersion idempotent in your code path by catching this error and treating it as 'already applied' for retried migrations
  4. Deduplicate version dumps before replaying them into storage

Example fix

// before
await storage.workspaces.createVersion({ id: versionId, workspaceId, versionNumber, config });
// after
const existing = await storage.workspaces.getVersionById(versionId);
if (!existing) {
  await storage.workspaces.createVersion({ id: crypto.randomUUID(), workspaceId, versionNumber, config });
}
Defensive patterns

Strategy: try-catch

Validate before calling

const exists = await storage.workspaces.getVersionById(versionId);
if (exists) return exists; // idempotent no-op

Try / catch

try {
  await storage.workspaces.createVersion({ id: newId, workspaceId, versionNumber, config });
} catch (err) {
  if (err instanceof Error && err.message === `Version with id ${newId} already exists`) {
    return; // already applied — treat as idempotent success
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling createVersion({ id: '<existing-version-id>', ... }) with a reused or hardcoded id; retrying a createVersion call that actually succeeded the first time; generating ids with Math.random()-style code that collides in tests; passing the workspace id as the version id.

Common situations: Custom migration scripts replaying version dumps without deduplicating; test fixtures re-seeding the same fixture id into a shared storage instance; idempotency attempts that reuse ids instead of checking existence first.

Related errors


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