Skip to content

POST /api/agents/threads returns 500 create_failed when alias already exists (alias=ui:<uuid>) #1369

@rowan-stein

Description

@rowan-stein

User report

  • Cannot send message to newly created agent because creating a new agent thread fails.
  • Request: POST /api/agents/threads
  • Response: { error: "create_failed" } (HTTP 500)
  • Server log excerpt:
createThread persistence failed alias=ui:e0fecd81-5470-4514-9629-1b076fb6e4aa

Researcher specification

Root cause hypothesis:

  • Thread persistence fails due to a unique constraint violation on Thread.alias when the same alias is reused (e.g., duplicate request with alias: "ui:<uuid>").
  • The controller maps all persistence errors to 500 { error: 'create_failed' }, obscuring the specific unique constraint error.

Relevant code locations:

  • Controller: packages/platform-server/src/agents/threads.controller.ts (POST /api/agents/threads) – defaults alias to ui:${randomUUID()} when not provided.
  • Persistence: packages/platform-server/src/agents/agents.persistence.service.ts (createThreadWithInitialMessage) – uses tx.thread.create({ data: { alias, ... } }) inside a transaction.
  • Schema: packages/platform-server/prisma/schema.prismamodel Thread { alias String @unique ... }. Migration creates unique index Thread_alias_key.

Reproduction steps:

  1. Send POST to /api/agents/threads with body:
{
  "text": "hello",
  "agentNodeId": "<valid-agent-node-id>",
  "alias": "ui:11111111-1111-1111-1111-111111111111"
}
  1. Repeat the exact same request.
  2. Actual: second call returns 500 { "error": "create_failed" } and server logs createThread persistence failed alias=ui:....
  3. Expected: endpoint should be idempotent by alias and return the existing thread, or respond with a 409 conflict with a clear error code.

Proposed fix:

  • Make create thread idempotent by alias in AgentsPersistenceService.createThreadWithInitialMessage by using upsert:
    • tx.thread.upsert({ where: { alias }, update: {}, create: { alias, summary, parentId, assignedAgentNodeId } })
  • Alternatively, handle Prisma unique constraint and return 409 { error: 'thread_alias_conflict' }, but idempotent upsert is preferred.
  • Improve controller error mapping to avoid collapsing all DB errors into create_failed.

Test plan:

  • Add tests for duplicate alias behavior: first call creates, second call with same alias returns same thread (idempotent) without 500.
  • Optional: if not using upsert, verify 409 mapping for unique alias conflict.
  • Ensure acceptance of alias with colon and UUID format; add any necessary validation tests.

Notes:

  • No DB migration required for idempotent upsert; relies on existing unique index.
  • Keep global uniqueness of alias consistent with existing assumptions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions