Files
twenty/packages/twenty-server
Sonarly Claude Code 72e8175d9a Field creation fails with unhandled duplicate key error due to stale cache validation
https://sonarly.com/issue/8579?type=bug

Creating a field via POST /metadata fails when a field with the same name already exists on the same object, because the name-uniqueness validation checks a stale in-memory cache rather than the database, and the resulting DB constraint violation is not handled as a user-friendly error.

Fix: The fix adds handling for `WorkspaceMigrationRunnerException` in `fieldMetadataGraphqlApiExceptionHandler`. Previously, when the DB unique constraint `IDX_FIELD_METADATA_NAME_OBJECT_METADATA_ID_WORKSPACE_ID_UNIQUE` was violated (due to the stale-cache TOCTOU race condition), the resulting `WorkspaceMigrationRunnerException` fell through the handler unhandled and propagated to Sentry as an opaque error.

The fix intercepts that specific exception — where `code === EXECUTION_FAILED` and `errors.metadata.message` contains the unique constraint name — and converts it to a user-friendly `ConflictError("A field with this name already exists on this object")`.

This is the minimal, targeted fix: it handles the DB constraint as the last line of defense, which is exactly the role the constraint was added to serve, without touching the cache layer or the migration runner itself.

```typescript file=packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/field-metadata-graphql-api-exception-handler.util.ts lines=17-40
import {
  WorkspaceMigrationRunnerException,
  WorkspaceMigrationRunnerExceptionCode,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/exceptions/workspace-migration-runner.exception';

// ...

  if (
    error instanceof WorkspaceMigrationRunnerException &&
    error.code === WorkspaceMigrationRunnerExceptionCode.EXECUTION_FAILED &&
    error.errors?.metadata?.message?.includes(
      'IDX_FIELD_METADATA_NAME_OBJECT_METADATA_ID_WORKSPACE_ID_UNIQUE',
    )
  ) {
    throw new ConflictError(
      new Error('A field with this name already exists on this object'),
    );
  }
```
2026-03-04 04:00:05 +00:00
..
2025-12-17 08:48:17 +01:00
2026-02-23 19:57:02 +01:00