mastra-ai/mastra · error · Error

Version number ${input.versionNumber} already exists for pro

Error message

Version number ${input.versionNumber} already exists for prompt block ${input.blockId}

What it means

InMemoryPromptBlockStorage.createVersion() throws this when a version with the same (blockId, versionNumber) pair already exists in the promptBlockVersions store. The library enforces unique version numbers per prompt block so version history stays monotonic and addressable. The version id is checked separately just before this check.

Source

Thrown at packages/core/src/storage/domains/prompt-blocks/inmemory.ts:186

      perPage: perPageForResponse,
      hasMore: offset + perPage < clonedBlocks.length,
    };
  }

  // ==========================================================================
  // Prompt Block Version Methods
  // ==========================================================================

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

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

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

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

  async getVersion(id: string): Promise<PromptBlockVersion | null> {
    const version = this.db.promptBlockVersions.get(id);
    return version ? this.deepCopyVersion(version) : null;
  }

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Query listVersions(blockId) first and compute the next versionNumber as max(existing)+1 before calling createVersion.
  2. Generate a fresh version id (crypto.randomUUID()) so the id-uniqueness check never collides, and only reuse versionNumber for idempotent replays you intend to reject.
  3. Wrap createVersion in try-catch and treat this message as 'already applied' if the replay is intentional.
  4. Clear the in-memory store (or use a fresh instance) between test/seed runs.

Example fix

// before
await storage.promptBlocks.createVersion({ id, blockId, versionNumber: 2, content });
// after
const { versions } = await storage.promptBlocks.listVersions(blockId, { perPage: false });
const next = versions.reduce((m, v) => Math.max(m, v.versionNumber), 0) + 1;
await storage.promptBlocks.createVersion({ id: crypto.randomUUID(), blockId, versionNumber: next, content });
Defensive patterns

Strategy: validation

Validate before calling

const { versions } = await storage.promptBlocks.listVersions(blockId, { perPage: false });
if (versions.some(v => v.versionNumber === nextVersionNumber)) {
  throw new Error(`versionNumber ${nextVersionNumber} already used for block ${blockId}`);
}

Type guard

function versionNumberIsFree(versions: { versionNumber: number }[], n: number): boolean {
  return !versions.some(v => v.versionNumber === n);
}

Try / catch

try {
  await storage.promptBlocks.createVersion(input);
} catch (e) {
  if (e instanceof Error && e.message.includes('already exists for prompt block')) {
    return; // idempotent replay: version already recorded
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling storage.promptBlocks.createVersion({ id: newId, blockId: 'b1', versionNumber: 2, ... }) when a version with blockId 'b1' and versionNumber 2 was already created (e.g. by a prior createVersion call or a seed routine like seedAgent that calls create->createVersion internally).

Common situations: Re-running a seeding/import script without clearing the store; retrying a failed request after the first attempt actually succeeded; concurrent writers racing to insert the next version number; hardcoding versionNumber instead of computing max+1.

Related errors


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