{"record":{"id":"559308c6be8f434a","repo":"Dokploy/dokploy","slug":"conflict-559308","errorCode":"CONFLICT","errorMessage":"A tag with this name already exists in your organization","messagePattern":"A tag with this name already exists in your organization","errorType":"exception","errorClass":"TRPCError","httpStatus":409,"severity":"warning","filePath":"apps/dokploy/server/api/routers/tag.ts","lineNumber":37,"sourceCode":"\t\t.input(apiCreateTag)\n\t\t.mutation(async ({ input, ctx }) => {\n\t\t\ttry {\n\t\t\t\tconst newTag = await db\n\t\t\t\t\t.insert(tags)\n\t\t\t\t\t.values({\n\t\t\t\t\t\tname: input.name,\n\t\t\t\t\t\tcolor: input.color,\n\t\t\t\t\t\torganizationId: ctx.session.activeOrganizationId,\n\t\t\t\t\t})\n\t\t\t\t\t.returning();\n\n\t\t\t\treturn newTag[0];\n\t\t\t} catch (error) {\n\t\t\t\tif (\n\t\t\t\t\terror instanceof Error &&\n\t\t\t\t\terror.message.includes(\"unique_org_tag_name\")\n\t\t\t\t) {\n\t\t\t\t\tthrow new TRPCError({\n\t\t\t\t\t\tcode: \"CONFLICT\",\n\t\t\t\t\t\tmessage: \"A tag with this name already exists in your organization\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tthrow new TRPCError({\n\t\t\t\t\tcode: \"BAD_REQUEST\",\n\t\t\t\t\tmessage: `Error creating tag: ${error instanceof Error ? error.message : error}`,\n\t\t\t\t\tcause: error,\n\t\t\t\t});\n\t\t\t}\n\t\t}),\n\n\tall: protectedProcedure.query(async ({ ctx }) => {\n\t\ttry {\n\t\t\tconst organizationTags = await db.query.tags.findMany({\n\t\t\t\twhere: eq(tags.organizationId, ctx.session.activeOrganizationId),\n\t\t\t\torderBy: (tags, { asc }) => [asc(tags.name)],\n\t\t\t});","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/Dokploy/dokploy/blob/546686ea3587f12ec5652217dedd9f7960fb6d15/apps/dokploy/server/api/routers/tag.ts#L19-L55","documentation":"Thrown by tag.create when the underlying Postgres insert violates the unique_org_tag_name constraint (tag name unique per organization). The catch inspects the driver error message for the constraint name and maps it to a 409 CONFLICT with a human-readable message.","triggerScenarios":"Calling tag.create({ name }) with a name that already exists (case-sensitively, per the constraint definition) in the same organization — e.g. creating 'production' when 'production' already exists.","commonSituations":"Duplicate submit/double click creating the tag twice; teams independently creating tags like 'prod' or 'client-a'; whitespace or casing differences bypassing client-side dedupe but not the DB constraint.","solutions":["List existing tags (tag.list) and reuse the existing tag instead of creating a new one","If the name is taken, pick a different name or namespace it (e.g. 'team-a/prod')","Trim/normalize tag names client-side before submit to avoid accidental duplicates"],"exampleFix":"// before\nawait api.tag.create({ name: 'production' });\n// after\nconst tags = await api.tag.list();\nconst existing = tags.find(t => t.name === 'production');\nif (!existing) await api.tag.create({ name: 'production' });","handlingStrategy":"validation","validationCode":"const tags = await api.tag.list();\nconst name = newName.trim();\nif (!tags.some(t => t.name === name)) {\n  await api.tag.create({ name });\n}","typeGuard":null,"tryCatchPattern":"try { await api.tag.create({ name }); }\ncatch (e) { if (e.shape?.data?.code === 'CONFLICT') reuseExistingTag(name); else throw e; }","preventionTips":["Load existing tags before showing the create form","Trim and normalize names client-side","Disable submit during in-flight creates to prevent doubles"],"tags":["tag","duplicate","conflict","postgres","dokploy","trpc"],"backgroundTag":"unique-constraint-violation","analyzedSha":"546686ea3587f12ec5652217dedd9f7960fb6d15","analyzedAt":"2026-08-27T05:18:58.095Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}