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

  1. Check existence first with GET the agent by ID and use the update endpoint instead of create if it exists
  2. Provide a different explicit `id` for the new agent
  3. Rename the agent so the derived slug is unique
  4. 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

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


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