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.prisma – model Thread { alias String @unique ... }. Migration creates unique index Thread_alias_key.
Reproduction steps:
- Send POST to
/api/agents/threads with body:
{
"text": "hello",
"agentNodeId": "<valid-agent-node-id>",
"alias": "ui:11111111-1111-1111-1111-111111111111"
}
- Repeat the exact same request.
- Actual: second call returns 500
{ "error": "create_failed" } and server logs createThread persistence failed alias=ui:....
- 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.
User report
POST /api/agents/threads{ error: "create_failed" }(HTTP 500)Researcher specification
Root cause hypothesis:
Thread.aliaswhen the same alias is reused (e.g., duplicate request withalias: "ui:<uuid>").{ error: 'create_failed' }, obscuring the specific unique constraint error.Relevant code locations:
packages/platform-server/src/agents/threads.controller.ts(POST /api/agents/threads) – defaultsaliastoui:${randomUUID()}when not provided.packages/platform-server/src/agents/agents.persistence.service.ts(createThreadWithInitialMessage) – usestx.thread.create({ data: { alias, ... } })inside a transaction.packages/platform-server/prisma/schema.prisma–model Thread { alias String @unique ... }. Migration creates unique indexThread_alias_key.Reproduction steps:
/api/agents/threadswith body:{ "text": "hello", "agentNodeId": "<valid-agent-node-id>", "alias": "ui:11111111-1111-1111-1111-111111111111" }{ "error": "create_failed" }and server logscreateThread persistence failed alias=ui:....Proposed fix:
AgentsPersistenceService.createThreadWithInitialMessageby usingupsert:tx.thread.upsert({ where: { alias }, update: {}, create: { alias, summary, parentId, assignedAgentNodeId } }){ error: 'thread_alias_conflict' }, but idempotent upsert is preferred.create_failed.Test plan:
aliaswith colon and UUID format; add any necessary validation tests.Notes: