bytedance/deer-flow · warning · HTTPException

Agent '{normalized_name}' already exists

Error message

Agent '{normalized_name}' already exists

What it means

409 from POST `/agents`: the store raised `AgentExistsError` during `create` — a config for the (lowercased) name already exists in the current user's scope. Creation is an atomic check-and-write in the store, so racing creates also surface here.

Source

Thrown at backend/app/gateway/routers/agents.py:344

    if request.skills is not None:
        config_data["skills"] = request.skills
    # model / model_settings / thinking_enabled / reasoning_effort (issue #4336).
    _apply_model_behavior(config_data, request)

    store = get_agent_store()

    def _create_agent() -> AgentResponse:
        # Worker thread: existence checks + persistence (file IO or a DB round
        # trip) must stay off the event loop.
        store.create(normalized_name, config_data, request.soul, user_id=user_id)
        logger.info("Created agent '%s'", normalized_name)
        agent_cfg = load_agent_config(normalized_name, user_id=user_id)
        return _agent_config_to_response(agent_cfg, include_soul=True, user_id=user_id)

    try:
        return await asyncio.to_thread(_create_agent)
    except AgentExistsError:
        raise HTTPException(status_code=409, detail=f"Agent '{normalized_name}' already exists")
    except Exception as e:
        logger.error(f"Failed to create agent '{request.name}': {e}", exc_info=True)
        raise HTTPException(status_code=500, detail=f"Failed to create agent: {str(e)}")


@router.put(
    "/agents/{name}",
    response_model=AgentResponse,
    summary="Update Custom Agent",
    description="Update an existing custom agent's config and/or SOUL.md.",
)
async def update_agent(name: str, request: AgentUpdateRequest) -> AgentResponse:
    """Update an existing custom agent.

    Args:
        name: The agent name.
        request: The update request (all fields optional).

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Pick a different name, or PUT to update the existing agent instead of POSTing a duplicate
  2. Pre-check with GET `/agents/check` (case-insensitive availability) before showing the create button
  3. Guard the UI submit button against double clicks

Example fix

# before
POST /agents { name: 'summarizer' }  # exists -> 409
# after
GET /agents/check?name=summarizer  # taken -> offer update
PUT /agents/summarizer { ... }
Defensive patterns

Strategy: validation

Validate before calling

const check = await api.checkAgentName(name); // GET /agents/check
if (!check.valid || !check.available) {
  throw new Error(`name taken/invalid: ${name}`);
}
await api.createAgent({ ...body, name });

Try / catch

try { return await api.createAgent(body); }
catch (e) {
  if (e.status === 409 && /already exists/.test(e.detail)) {
    return api.updateAgent(body.name.toLowerCase(), body); // upsert semantics
  }
  throw e;
}

Prevention

When it happens

Trigger: POST `/agents/my-agent` twice; creating 'MyAgent' when 'myagent' exists (normalization makes names case-insensitive); double-clicked submit buttons or retried requests.

Common situations: Frontends without disabled-state on submit; retries after network errors that actually succeeded server-side; users assuming names are case-sensitive.

Related errors


AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14). Data as JSON: /api/errors/fe2a1719020c8196. Report an issue: GitHub.