mastra-ai/mastra · error · HTTPException
Agent with id ${id} already exists
Error message
Agent with id ${id} already exists What it means
Thrown with HTTP 409 (Conflict) when creating a stored agent whose derived or provided `id` already exists in the agents store — `agentsStore.getById(id)` returned an existing record. Agent IDs are unique keys, so the create is refused to avoid silently overwriting an existing agent.
Source
Thrown at packages/server/src/server/handlers/stored-agents.ts:606
const agentsStore = await storage.getStore('agents');
if (!agentsStore) {
throw new HTTPException(500, { message: 'Agents storage domain is not available' });
}
// Derive ID from name if not explicitly provided
const id = providedId || toSlug(name);
if (!id) {
throw new HTTPException(400, {
message: 'Could not derive agent ID from name. Please provide an explicit id.',
});
}
// Check if agent with this ID already exists
const existing = await agentsStore.getById(id);
if (existing) {
throw new HTTPException(409, { message: `Agent with id ${id} already exists` });
}
// Force authorId from the authenticated caller; ignore any body-provided value.
// No owner = always public (no auth / no user context).
// With an owner, respect the client's choice, defaulting to 'private'.
const authorId = getCallerAuthorId(requestContext) ?? undefined;
const visibility = authorId ? (bodyVisibility ?? 'private') : 'public';
// Reject oversized avatar images before writing to storage.
validateMetadataAvatarUrl(metadata);
// Model policy enforcement is intentionally not done on save: each UI
// surface gates its own model picker via ModelPolicyProvider, and the
// policy is surface-scoped (builder vs editor). Re-introducing a single
// server-side check here would either over-enforce on the editor or
// under-enforce on the builder until per-surface enforcement lands.
const resolvedBrowser = await resolveBrowserField(browser, mastra);View on GitHub (pinned to 75dd419e61)
Solutions
- Check existence first with GET the agent by ID and use the update endpoint instead of create if it exists
- Provide a different explicit `id` for the new agent
- Rename the agent so the derived slug is unique
- Make create scripts idempotent: catch 409 and treat as 'already created' or upsert via update
Example fix
// before
await createStoredAgent({ id: 'support-bot', name: 'Support Bot' }); // 409 on rerun
// after
const existing = await getStoredAgent('support-bot');
if (existing) {
await updateStoredAgent('support-bot', { instructions });
} else {
await createStoredAgent({ id: 'support-bot', name: 'Support Bot' });
} Defensive patterns
Strategy: validation
Validate before calling
const existing = await getStoredAgent(id).catch(() => null);
if (existing) {
return updateStoredAgent(id, patch); // upsert-style
} Type guard
null
Try / catch
try {
await createStoredAgent(input);
} catch (e) {
if (isHttpError(e) && e.status === 409) {
return updateStoredAgent(input.id, input); // treat as upsert
}
throw e;
} Prevention
- Make seed/bootstrap scripts idempotent (check-then-create or upsert)
- Use unique, prefixed IDs for generated agents (e.g. `org:team:assistant`)
- Generate IDs with UUIDs/nanoids when names are user-supplied and may collide
When it happens
Trigger: POST /api/agents where the explicit `id` in the body, or the slug derived from `name`, matches an already-stored agent (draft or published).
Common situations: Re-running a seed/bootstrap script that creates agents with fixed IDs; two users independently naming agents the same thing; retrying a create after a network timeout when the first request actually succeeded; an ID derived from a very generic agent name like 'assistant'.
Related errors
- MCP client with id ${id} already exists
- Scorer definition with id ${id} already exists
- Skill with id ${id} already exists
- Skipped: Scorer ${filename} already exists at ${scorersPath}
- Skill with id "${id}" already exists.
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/f6163e4e49237579.
Report an issue: GitHub.