{"record":{"id":"75ec665c8a06214d","repo":"Budibase/budibase","slug":"a-custom-rest-template-named-name-trim-alre","errorCode":null,"errorMessage":"A custom REST template named \"${name.trim()}\" already exists","messagePattern":"A custom REST template named \"(.+?)\" already exists","errorType":"http","errorClass":"HTTPError","httpStatus":409,"severity":"error","filePath":"packages/server/src/sdk/workspace/restTemplates.ts","lineNumber":102,"sourceCode":"\nconst createWithoutLock = async ({\n  name,\n  description,\n  data,\n  fileExtension,\n  operationsCount,\n}: CreateCustomRestTemplateParams): Promise<RestTemplate> => {\n  const db = context.getWorkspaceDB()\n  const normalizedName = kebabCase(name)\n  if (!normalizedName) {\n    throw new HTTPError(\"Template name must contain letters or numbers\", 400)\n  }\n\n  const existingTemplate = (await fetch()).find(\n    template => kebabCase(template.name) === normalizedName\n  )\n  if (existingTemplate) {\n    throw new HTTPError(\n      `A custom REST template named \"${name.trim()}\" already exists`,\n      409\n    )\n  }\n\n  const restTemplateId = dbCore.generateRestTemplateID()\n  const existing = await db.tryGet<CustomRestTemplateDocument>(restTemplateId)\n  if (existing) {\n    throw new HTTPError(\n      `A custom REST template named \"${name.trim()}\" already exists`,\n      409\n    )\n  }\n\n  const folder = getObjectStoreFolder(restTemplateId)\n  const objectStoreKey = `${folder}/openapi.${fileExtension}`\n  const document: CustomRestTemplateDocument = {\n    _id: restTemplateId,","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/restTemplates.ts#L84-L120","documentation":"A 409 HTTPError thrown when a template with the same kebab-cased name already exists, detected by scanning the workspace's existing templates via fetch(). This is the name-uniqueness check performed before generating the new template id.","triggerScenarios":"Calling create with a name whose kebabCase form equals an existing template's kebabCased name — including names differing only in case, spacing, or separators (\"My Template\" vs \"my-template\"), or the exact same create call submitted twice.","commonSituations":"User clicks 'Create' twice quickly; duplicating a template in the UI without renaming; two workspace admins creating identically named templates concurrently; kebab-case collisions like \"REST v2\" and \"rest-v2\".","solutions":["Check the returned 409 and surface 'name already in use' to the user, prompting for a new name","Pre-check with fetch() (list templates) and compare kebabCase(name) before creating","Append a distinguishing suffix (version, timestamp) to guarantee uniqueness","Deduplicate concurrent submissions by disabling the create action once in flight"],"exampleFix":"// before\nawait restTemplates.create({ name: \"My API\" }) // 409 if \"my-api\" exists\n// after\nconst exists = (await restTemplates.fetch()).some(t => kebabCase(t.name) === \"my-api\")\nif (!exists) await restTemplates.create({ name: \"My API\" })","handlingStrategy":"validation","validationCode":"const taken = (await restTemplates.fetch()).some(t => kebabCase(t.name) === kebabCase(name))\nif (taken) throw new Error(`A template named \"${name}\" already exists`)","typeGuard":"null","tryCatchPattern":"try {\n  await restTemplates.create({ name })\n} catch (e) {\n  if (e?.status === 409) {\n    // prompt the user for a different name\n    return\n  }\n  throw e\n}","preventionTips":["Compare names after kebabCase since 'My API' and 'my-api' collide","Disable the create button while a request is in flight to prevent double submits","Auto-suffix duplicate names in batch/automation workflows","Keep the template list fresh so pre-checks see recent creations"],"tags":["http-409","duplicate","uniqueness","rest-templates"],"backgroundTag":"duplicate-name-conflict","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}