{"record":{"id":"d6deb1e313ae9d2c","repo":"Budibase/budibase","slug":"column-names-can-t-contain-special-characters","errorCode":null,"errorMessage":"Column names can't contain special characters","messagePattern":"Column names can't contain special characters","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/server/src/db/linkedRows/LinkController.ts","lineNumber":106,"sourceCode":"      includeDocs: IncludeDocs.INCLUDE,\n    })) as LinkDocument[]\n  }\n\n  /**\n   * Makes sure the passed in table schema contains valid relationship structures.\n   */\n  validateTable(table: Table) {\n    const usedAlready = []\n    for (let schema of Object.values(table.schema)) {\n      if (schema.type !== FieldType.LINK) {\n        continue\n      }\n      if (\n        schema.fieldName &&\n        !schema.autocolumn &&\n        !schema.fieldName.match(ValidColumnNameRegex)\n      ) {\n        throw new Error(\"Column names can't contain special characters\")\n      }\n      const unique = schema.tableId! + schema?.fieldName\n      if (usedAlready.indexOf(unique) !== -1) {\n        throw new Error(\n          \"Cannot re-use the linked column name for a linked table.\"\n        )\n      }\n      usedAlready.push(unique)\n    }\n  }\n\n  /**\n   * Returns whether the two link schemas are equal (in the important parts, not a pure equality check)\n   */\n  areLinkSchemasEqual(linkSchema1: FieldSchema, linkSchema2: FieldSchema) {\n    const compareFields = [\n      \"name\",\n      \"type\",","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/db/linkedRows/LinkController.ts#L88-L124","documentation":"`validateTable` in LinkController runs when a table is saved. For link-type schema entries with a fieldName (and not autocolumns), it enforces the ValidColumnNameRegex; names containing special characters (spaces, symbols, etc.) would break link document storage and lookups, so saving throws 'Column names can't contain special characters'.","triggerScenarios":"Saving a table whose link column name contains characters outside the allowed regex, e.g. \"My Links!\", \"user-roles #1\", or a name with spaces or emoji; renaming a link column via the API to a value with slashes or dots.","commonSituations":"Users create columns with friendly display names containing spaces or punctuation; an app imported from a CSV/Excel where headers became column names with special characters; API scripts generating column names from arbitrary labels.","solutions":["Rename the link column to only letters, digits and underscores (matching ValidColumnNameRegex), e.g. \"user_links\".","If importing data, sanitize headers to a safe charset before creating tables.","Use the column's display name feature for human-readable labels instead of encoding them in fieldName."],"exampleFix":"// before\n{ \"name\": \"Order Items!\", \"type\": \"link\" }\n// after\n{ \"name\": \"order_items\", \"type\": \"link\", \"displayName\": \"Order Items\" }","handlingStrategy":"validation","validationCode":"const ValidColumnNameRegex = /^[a-zA-Z0-9_]+$/\nfor (const [name, schema] of Object.entries(table.schema)) {\n  if (schema.type === \"link\" && !ValidColumnNameRegex.test(name)) {\n    throw new Error(`Link column '${name}' must only contain letters, digits and underscores`)\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await api.post(`/tables`, table)\n} catch (err) {\n  if (err.message.includes(\"special characters\")) {\n    table.schema = sanitizeColumnNames(table.schema)\n    return api.post(`/tables`, table)\n  }\n  throw err\n}","preventionTips":["Use snake_case identifiers for link columns and set display names separately.","Sanitize CSV/Excel headers before table import.","Regex-test generated column names in scripts before saving tables."],"tags":["database","tables","validation","naming","linked-rows"],"backgroundTag":"invalid-column-name","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}