From 7b48efb5d6c53f506c32529c3973bd5880a5ccd5 Mon Sep 17 00:00:00 2001 From: Marie <51697796+ijreilly@users.noreply.github.com> Date: Mon, 2 Feb 2026 18:11:20 +0100 Subject: [PATCH] Fix creation of objects with acronym names (e.g. "O&J") (#17633) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/twentyhq/twenty/issues/17544 **Problem** When users create custom objects with short acronym names like "O&J", the system generates an object name oJ. When creating relation fields, the morph field name was built using string concatenation: const morphFieldName = `target${capitalize("oJ")}`; // → "targetOJ" This produced "targetOJ", which failed validation because the camelCase check performed in `validateFlatFieldMetadataName` (camelCase(name) === name) returns "targetOj" for "targetOJ". The issue comes from consecutive camelCase() operations. **Solution** Actually, the `camelCase(name) === name` check is questionnable. What we want to check is that a name is in camelCase format, not that it corresponds to the camelCase version of a given string, while that's we are doing here. lodash does not provide camelCase validator, only camelCase convertor, so we used it as a way to validate the format of the name. We may feel like `camelCase(name) === name` checks whether a name is camel-cased, but in addition to that it is also checking for a camel case "idempotency" we don't necessarily have and do not need: for instance if an object's name is "iOS" (which could be inferred from a label "I O S"), it won't pass the check: camelCase("iOS") is "ios" and "ios" !== "iOS". The existing check with `STARTS_WITH_LOWER_CASE_AND_CONTAINS_ONLY_CAPS_AND_LOWER_LETTERS_AND_NUMBER_STRING_REGEX` acts as a camel case validator, so we don't need that camelCase() check. --- .../validate-flat-field-metadata-name.util.ts | 10 --- ...validate-flat-object-metadata-name.util.ts | 11 --- ...a-relation-update.integration-spec.ts.snap | 6 -- ...bject-metadata-v2.integration-spec.ts.snap | 90 ------------------- 4 files changed, 117 deletions(-) diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-flat-field-metadata-name.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-flat-field-metadata-name.util.ts index ba016193ec..877f98c309 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-flat-field-metadata-name.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-flat-field-metadata-name.util.ts @@ -1,5 +1,4 @@ import { msg, t } from '@lingui/core/macro'; -import camelCase from 'lodash.camelcase'; import { RESERVED_METADATA_NAME_KEYWORDS } from 'twenty-shared/metadata'; import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception'; @@ -38,15 +37,6 @@ export const validateFlatFieldMetadataName = ({ }); } - if (name !== camelCase(name)) { - errors.push({ - code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, - message: t`Name should be in camelCase`, - userFriendlyMessage: msg`Name should be in camelCase`, - value: name, - }); - } - if ( !name.match( STARTS_WITH_LOWER_CASE_AND_CONTAINS_ONLY_CAPS_AND_LOWER_LETTERS_AND_NUMBER_STRING_REGEX, diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/validators/utils/validate-flat-object-metadata-name.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/validators/utils/validate-flat-object-metadata-name.util.ts index 162b6dcba2..b645e13b4b 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/validators/utils/validate-flat-object-metadata-name.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/validators/utils/validate-flat-object-metadata-name.util.ts @@ -1,5 +1,4 @@ import { msg } from '@lingui/core/macro'; -import camelCase from 'lodash.camelcase'; import { RESERVED_METADATA_NAME_KEYWORDS } from 'twenty-shared/metadata'; import { type FlatObjectMetadataValidationError } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata-validation-error.type'; @@ -41,16 +40,6 @@ export const validateFlatObjectMetadataNames = ({ }); } - // CamelCase check - if (name !== camelCase(name)) { - errors.push({ - code: ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT, - message: `Name should be in camelCase`, - userFriendlyMessage: msg`Name should be in camelCase`, - value: name, - }); - } - // Format check if ( !name.match( diff --git a/packages/twenty-server/test/integration/metadata/suites/field-metadata/relation/__snapshots__/failing-field-metadata-relation-update.integration-spec.ts.snap b/packages/twenty-server/test/integration/metadata/suites/field-metadata/relation/__snapshots__/failing-field-metadata-relation-update.integration-spec.ts.snap index 4cb57b3c74..be5a250532 100644 --- a/packages/twenty-server/test/integration/metadata/suites/field-metadata/relation/__snapshots__/failing-field-metadata-relation-update.integration-spec.ts.snap +++ b/packages/twenty-server/test/integration/metadata/suites/field-metadata/relation/__snapshots__/failing-field-metadata-relation-update.integration-spec.ts.snap @@ -9,12 +9,6 @@ exports[`Field metadata relation update should fail relation when name is not in "fieldMetadata": [ { "errors": [ - { - "code": "INVALID_FIELD_INPUT", - "message": "Name should be in camelCase", - "userFriendlyMessage": "Name should be in camelCase", - "value": "New Name", - }, { "code": "INVALID_FIELD_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", diff --git a/packages/twenty-server/test/integration/metadata/suites/object-metadata/__snapshots__/failing-create-one-object-metadata-v2.integration-spec.ts.snap b/packages/twenty-server/test/integration/metadata/suites/object-metadata/__snapshots__/failing-create-one-object-metadata-v2.integration-spec.ts.snap index 043abfe4f1..94cf62dee3 100644 --- a/packages/twenty-server/test/integration/metadata/suites/object-metadata/__snapshots__/failing-create-one-object-metadata-v2.integration-spec.ts.snap +++ b/packages/twenty-server/test/integration/metadata/suites/object-metadata/__snapshots__/failing-create-one-object-metadata-v2.integration-spec.ts.snap @@ -6802,12 +6802,6 @@ exports[`Object metadata creation should fail v2 when namePlural is not camelCas "objectMetadata": [ { "errors": [ - { - "code": "INVALID_OBJECT_INPUT", - "message": "Name should be in camelCase", - "userFriendlyMessage": "Name should be in camelCase", - "value": "Not_Camel_Case", - }, { "code": "INVALID_OBJECT_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", @@ -7399,12 +7393,6 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only }, { "errors": [ - { - "code": "INVALID_FIELD_INPUT", - "message": "Name should be in camelCase", - "userFriendlyMessage": "Name should be in camelCase", - "value": "targetA a", - }, { "code": "INVALID_FIELD_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", @@ -7429,12 +7417,6 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only }, { "errors": [ - { - "code": "INVALID_FIELD_INPUT", - "message": "Name should be in camelCase", - "userFriendlyMessage": "Name should be in camelCase", - "value": "a a", - }, { "code": "INVALID_FIELD_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", @@ -7459,12 +7441,6 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only }, { "errors": [ - { - "code": "INVALID_FIELD_INPUT", - "message": "Name should be in camelCase", - "userFriendlyMessage": "Name should be in camelCase", - "value": "targetA a", - }, { "code": "INVALID_FIELD_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", @@ -7489,12 +7465,6 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only }, { "errors": [ - { - "code": "INVALID_FIELD_INPUT", - "message": "Name should be in camelCase", - "userFriendlyMessage": "Name should be in camelCase", - "value": "a a", - }, { "code": "INVALID_FIELD_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", @@ -7519,12 +7489,6 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only }, { "errors": [ - { - "code": "INVALID_FIELD_INPUT", - "message": "Name should be in camelCase", - "userFriendlyMessage": "Name should be in camelCase", - "value": "a a", - }, { "code": "INVALID_FIELD_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", @@ -7575,12 +7539,6 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only "objectMetadata": [ { "errors": [ - { - "code": "INVALID_OBJECT_INPUT", - "message": "Name should be in camelCase", - "userFriendlyMessage": "Name should be in camelCase", - "value": "a a", - }, { "code": "INVALID_OBJECT_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", @@ -8921,12 +8879,6 @@ exports[`Object metadata creation should fail v2 when nameSingular has invalid c }, { "errors": [ - { - "code": "INVALID_FIELD_INPUT", - "message": "Name should be in camelCase", - "userFriendlyMessage": "Name should be in camelCase", - "value": "targetΜ", - }, { "code": "INVALID_FIELD_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", @@ -8975,12 +8927,6 @@ exports[`Object metadata creation should fail v2 when nameSingular has invalid c }, { "errors": [ - { - "code": "INVALID_FIELD_INPUT", - "message": "Name should be in camelCase", - "userFriendlyMessage": "Name should be in camelCase", - "value": "targetΜ", - }, { "code": "INVALID_FIELD_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", @@ -10406,12 +10352,6 @@ exports[`Object metadata creation should fail v2 when nameSingular is not camelC }, { "errors": [ - { - "code": "INVALID_FIELD_INPUT", - "message": "Name should be in camelCase", - "userFriendlyMessage": "Name should be in camelCase", - "value": "targetNot_Camel_Case", - }, { "code": "INVALID_FIELD_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", @@ -10436,12 +10376,6 @@ exports[`Object metadata creation should fail v2 when nameSingular is not camelC }, { "errors": [ - { - "code": "INVALID_FIELD_INPUT", - "message": "Name should be in camelCase", - "userFriendlyMessage": "Name should be in camelCase", - "value": "Not_Camel_Case", - }, { "code": "INVALID_FIELD_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", @@ -10466,12 +10400,6 @@ exports[`Object metadata creation should fail v2 when nameSingular is not camelC }, { "errors": [ - { - "code": "INVALID_FIELD_INPUT", - "message": "Name should be in camelCase", - "userFriendlyMessage": "Name should be in camelCase", - "value": "targetNot_Camel_Case", - }, { "code": "INVALID_FIELD_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", @@ -10496,12 +10424,6 @@ exports[`Object metadata creation should fail v2 when nameSingular is not camelC }, { "errors": [ - { - "code": "INVALID_FIELD_INPUT", - "message": "Name should be in camelCase", - "userFriendlyMessage": "Name should be in camelCase", - "value": "Not_Camel_Case", - }, { "code": "INVALID_FIELD_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", @@ -10526,12 +10448,6 @@ exports[`Object metadata creation should fail v2 when nameSingular is not camelC }, { "errors": [ - { - "code": "INVALID_FIELD_INPUT", - "message": "Name should be in camelCase", - "userFriendlyMessage": "Name should be in camelCase", - "value": "Not_Camel_Case", - }, { "code": "INVALID_FIELD_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", @@ -10582,12 +10498,6 @@ exports[`Object metadata creation should fail v2 when nameSingular is not camelC "objectMetadata": [ { "errors": [ - { - "code": "INVALID_OBJECT_INPUT", - "message": "Name should be in camelCase", - "userFriendlyMessage": "Name should be in camelCase", - "value": "Not_Camel_Case", - }, { "code": "INVALID_OBJECT_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters",