mastra-ai/mastra · error
Skill with id ${skill.id} already exists
Error message
Skill with id ${skill.id} already exists What it means
The in-memory skills storage create() checks its skills map and rejects creation when a skill with the same id already exists. Ids are primary keys, so create is insert-only and duplicates are an error, not an overwrite.
Source
Thrown at packages/core/src/storage/domains/skills/inmemory.ts:51
async dangerouslyClearAll(): Promise<void> {
this.db.skills.clear();
this.db.skillVersions.clear();
}
// ==========================================================================
// Skill CRUD Methods
// ==========================================================================
async getById(id: string): Promise<StorageSkillType | null> {
const config = this.db.skills.get(id);
return config ? this.deepCopyConfig(config) : null;
}
async create(input: { skill: StorageCreateSkillInput }): Promise<StorageSkillType> {
const { skill } = input;
if (this.db.skills.has(skill.id)) {
throw new Error(`Skill with id ${skill.id} already exists`);
}
const now = new Date();
const visibility = skill.visibility ?? (skill.authorId ? 'private' : undefined);
const newConfig: StorageSkillType = {
id: skill.id,
status: 'draft',
activeVersionId: undefined,
authorId: skill.authorId,
visibility,
favoriteCount: 0,
createdAt: now,
updatedAt: now,
};
this.db.skills.set(skill.id, newConfig);
// Extract config fields from the flat input (everything except record fields)View on GitHub (pinned to 75dd419e61)
Solutions
- Check existence first with this.db.skills.has(id) equivalent / a get call, then create or update accordingly.
- Make seeds idempotent: skip or update when the id already exists instead of always creating.
- Use unique ids per run (suffix with timestamp/uuid) when duplicates are expected.
- Clear the store between test runs.
Example fix
// before
await skillsStorage.create({ skill: { id: 'deploy', ...cfg } }); // throws on 2nd run
// after
const existing = await skillsStorage.get({ id: 'deploy' });
if (!existing) await skillsStorage.create({ skill: { id: 'deploy', ...cfg } });
else await skillsStorage.update({ id: 'deploy', ...cfg }); Defensive patterns
Strategy: validation
Validate before calling
const existing = await storage.get({ id: skill.id });
if (existing) throw new Error(`skill ${skill.id} already exists`); Type guard
async function canCreate(storage: InMemorySkillsStorage, id: string): Promise<boolean> {
return !(await storage.get({ id }));
} Try / catch
try {
return await storage.create({ skill });
} catch (e) {
if (e instanceof Error && e.message.includes('already exists')) {
return storage.update({ ...skill });
}
throw e;
} Prevention
- Make seed functions idempotent (check-before-create or update-on-exists).
- Generate unique ids (uuid/slug+timestamp) when creating user-driven skills.
- Reset the in-memory store between test runs.
- Treat create as insert-only; route re-creation attempts to update.
When it happens
Trigger: Calling create({ skill: { id: 'x', ... } }) twice for the same id, or via seedSkill re-running against an already-seeded store; re-running a seed/demo script on a warm process.
Common situations: Non-idempotent seed functions run on app startup; test setup reusing the same in-memory DB across cases; retrying a request after a timeout when the first attempt actually succeeded.
Related errors
- Version number ${input.versionNumber} already exists for pro
- Schedule ${schedule.id} already exists
- Scorer definition with id ${scorerDefinition.id} already exi
- Version with id ${input.id} already exists
- Skill with id ${id} not found
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/da49535f9ab5e426.
Report an issue: GitHub.