mastra-ai/mastra · error · Error

Version with id ${input.id} already exists

Error message

Version with id ${input.id} already exists

What it means

Agent versions are immutable and identified by unique IDs; `createVersion` throws if `this.db.agentVersions` already contains `input.id`. Immutability means a conflicting ID can never be overwritten — a new version row with a new ID is required.

Source

Thrown at packages/core/src/storage/domains/agents/inmemory.ts:224

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

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

  // ==========================================================================
  // Agent Version Methods
  // ==========================================================================

  async createVersion(input: CreateVersionInput): Promise<AgentVersion> {
    // Check if version with this ID already exists (versions are immutable)
    if (this.db.agentVersions.has(input.id)) {
      throw new Error(`Version with id ${input.id} already exists`);
    }

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

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

    // Deep clone before storing to prevent external mutation
    this.db.agentVersions.set(input.id, this.deepCopyVersion(version));
    return this.deepCopyVersion(version);
  }

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Check `getVersion(id)` (or the map) before creating; skip or fetch the existing version
  2. Generate unique version IDs (e.g. crypto.randomUUID()) rather than deterministic reused ones
  3. Treat the throw as idempotent success in retry paths

Example fix

// before
await agents.createVersion({ id: 'v1', agentId: 'a1', versionNumber: 1, ... });
// after
const id = crypto.randomUUID();
await agents.createVersion({ id, agentId: 'a1', versionNumber: 1, ... });
Defensive patterns

Strategy: try-catch

Validate before calling

const existing = await agentsDomain.getVersion({ versionId: version.id });
if (existing) {
  return existing; // already created
}

Type guard

null

Try / catch

try {
  return await agentsDomain.createVersion(version);
} catch (e) {
  if (e instanceof Error && /Version with id .* already exists/.test(e.message)) {
    return agentsDomain.getVersion({ versionId: version.id });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling `createVersion` with an `id` that already exists in the versions store — e.g. deterministic IDs derived from (agentId, versionNumber) that were already created, or replayed/duplicated requests.

Common situations: Retry logic re-submitting the same version creation; seed scripts run twice; deriving version IDs from content or number without checking existence first.

Related errors


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