Skip to content

feat(server): enforce userFriendlyMessage on all exceptions#16589

Merged
FelixMalfait merged 3 commits intomainfrom
feat/enforce-user-friendly-exception-messages
Dec 16, 2025
Merged

feat(server): enforce userFriendlyMessage on all exceptions#16589
FelixMalfait merged 3 commits intomainfrom
feat/enforce-user-friendly-exception-messages

Conversation

@FelixMalfait
Copy link
Copy Markdown
Member

@FelixMalfait FelixMalfait commented Dec 16, 2025

Summary

This PR enforces that all custom exceptions must provide a userFriendlyMessage, ensuring end users always see readable error messages.

Changes

Core Changes

  • CustomException simplified: Removed the ForceFriendlyMessage generic parameter - userFriendlyMessage is now always required
  • Type safety: The constructor now requires { userFriendlyMessage: MessageDescriptor } (no longer optional)

Updated Files

  • 74+ exception classes updated to provide default user-friendly messages using Lingui msg macro
  • Each exception class has a sensible fallback message (e.g., msg\An authentication error occurred.``)
  • Exception classes that had code-specific message maps retain their behavior

Benefits

  • Compile-time enforcement: Forgetting to add a user-friendly message now causes a TypeScript error
  • Better UX: End users always see a localized, human-readable error message
  • Simpler API: No more boolean generic parameter to think about

Testing

  • npx nx run twenty-server:typecheck passes
  • npx nx run twenty-server:lint passes

Note

Enforces userFriendlyMessage on CustomException and updates all exception classes to supply localized default messages, with filters/tests adjusted accordingly.

  • Core:
    • Enforce required userFriendlyMessage in CustomException (remove optional generic; constructor now requires { userFriendlyMessage: MessageDescriptor }).
  • Exceptions:
    • Update ~70+ exception classes to set default localized messages via Lingui msg maps and pass them in constructors (e.g., AuthException, ObjectMetadataException, FieldMetadataException, etc.).
    • Add fallback messages where needed (e.g., INTERNAL_SERVER_ERROR or domain-specific defaults).
  • HTTP/GraphQL Filters:
    • Ensure fallbacks create UnknownException with msg for user-friendly text in REST/GraphQL exception filters.
  • Tests:
    • Adjust unit tests to pass userFriendlyMessage to exceptions.
    • Update Jest snapshots to include extensions.userFriendlyMessage or message objects where applicable.

Written by Cursor Bugbot for commit 221004f. This will update automatically on new commits. Configure here.

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the final PR Bugbot will review for you during this billing cycle

Your free Bugbot reviews will reset on January 15

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 88 files

Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed.

Prompt for AI agents (all 1 issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/twenty-server/src/engine/metadata-modules/view-filter/filters/view-filter-rest-api-exception.filter.ts">

<violation number="1" location="packages/twenty-server/src/engine/metadata-modules/view-filter/filters/view-filter-rest-api-exception.filter.ts:85">
P2: Use Lingui&#39;s `msg` macro instead of a plain object for `userFriendlyMessage`. This ensures the message is picked up by Lingui&#39;s extraction process for translation and maintains consistency with other exception classes in the codebase (e.g., `ViewFilterException`).</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

'Internal server error',
'INTERNAL_ERROR',
{
userFriendlyMessage: {
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Dec 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Use Lingui's msg macro instead of a plain object for userFriendlyMessage. This ensures the message is picked up by Lingui's extraction process for translation and maintains consistency with other exception classes in the codebase (e.g., ViewFilterException).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/twenty-server/src/engine/metadata-modules/view-filter/filters/view-filter-rest-api-exception.filter.ts, line 85:

<comment>Use Lingui&#39;s `msg` macro instead of a plain object for `userFriendlyMessage`. This ensures the message is picked up by Lingui&#39;s extraction process for translation and maintains consistency with other exception classes in the codebase (e.g., `ViewFilterException`).</comment>

<file context>
@@ -81,6 +81,12 @@ export class ViewFilterRestApiExceptionFilter implements ExceptionFilter {
       &#39;Internal server error&#39;,
       &#39;INTERNAL_ERROR&#39;,
+      {
+        userFriendlyMessage: {
+          id: &#39;internal.error&#39;,
+          message: &#39;An unexpected error occurred.&#39;,
</file context>

✅ Addressed in 11f589a

@FelixMalfait FelixMalfait force-pushed the feat/enforce-user-friendly-exception-messages branch 2 times, most recently from 11f589a to 7ae1359 Compare December 16, 2025 12:48
@FelixMalfait FelixMalfait force-pushed the feat/enforce-user-friendly-exception-messages branch from 7ae1359 to eab4e7e Compare December 16, 2025 13:11
Comment on lines +26 to +36
USE_SSO_AUTH: msg`Please use single sign-on to authenticate.`,
SIGNUP_DISABLED: msg`Sign up is disabled.`,
GOOGLE_API_AUTH_DISABLED: msg`Google API authentication is disabled.`,
MICROSOFT_API_AUTH_DISABLED: msg`Microsoft API authentication is disabled.`,
MISSING_ENVIRONMENT_VARIABLE: msg`A required configuration is missing.`,
INVALID_JWT_TOKEN_TYPE: msg`Invalid authentication token.`,
TWO_FACTOR_AUTHENTICATION_PROVISION_REQUIRED: msg`Two-factor authentication setup is required.`,
TWO_FACTOR_AUTHENTICATION_VERIFICATION_REQUIRED: msg`Two-factor authentication verification is required.`,
USER_ALREADY_EXISTS: msg`A user with this email already exists.`,
INTERNAL_SERVER_ERROR: msg`An unexpected error occurred.`,
};

This comment was marked as outdated.

- Make userFriendlyMessage required in CustomException (no longer optional)
- Remove ForceFriendlyMessage generic parameter as it's no longer needed
- Update all 74+ exception classes to provide default user-friendly messages
- Each exception class now has a sensible default message using Lingui msg macro
- This ensures end users always see a readable error message
@FelixMalfait FelixMalfait force-pushed the feat/enforce-user-friendly-exception-messages branch from eab4e7e to 08af613 Compare December 16, 2025 13:16
@github-actions
Copy link
Copy Markdown
Contributor

📊 API Changes Report

GraphQL Schema Changes

GraphQL Schema Changes

[error] Error: Unable to read JSON file: /home/runner/work/twenty/twenty/main-schema-introspection.json: Not valid JSON content
at JsonFileLoader.handleFileContent (/opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/json-file-loader/cjs/index.js:147:19)
at /opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/json-file-loader/cjs/index.js:95:43
at async Promise.all (index 0)
at async JsonFileLoader.load (/opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/json-file-loader/cjs/index.js:88:9)
at async /opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/load/cjs/load-typedefs/load-file.js:15:39
at async Promise.all (index 4)
at async loadFile (/opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/load/cjs/load-typedefs/load-file.js:13:9)
at async /opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/load/cjs/load-typedefs/collect-sources.js:200:25
Error: Unable to read JSON file: /home/runner/work/twenty/twenty/main-schema-introspection.json: Not valid JSON content
at JsonFileLoader.handleFileContent (/opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/json-file-loader/cjs/index.js:147:19)
at /opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/json-file-loader/cjs/index.js:95:43
at async Promise.all (index 0)
at async JsonFileLoader.load (/opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/json-file-loader/cjs/index.js:88:9)
at async /opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/load/cjs/load-typedefs/load-file.js:15:39
at async Promise.all (index 4)
at async loadFile (/opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/load/cjs/load-typedefs/load-file.js:13:9)
at async /opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/load/cjs/load-typedefs/collect-sources.js:200:25
⚠️ Breaking changes or errors detected in GraphQL schema

[error] Error: Unable to read JSON file: /home/runner/work/twenty/twenty/main-schema-introspection.json: Not valid JSON content
    at JsonFileLoader.handleFileContent (/opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/json-file-loader/cjs/index.js:147:19)
    at /opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/json-file-loader/cjs/index.js:95:43
    at async Promise.all (index 0)
    at async JsonFileLoader.load (/opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/json-file-loader/cjs/index.js:88:9)
    at async /opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/load/cjs/load-typedefs/load-file.js:15:39
    at async Promise.all (index 4)
    at async loadFile (/opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/load/cjs/load-typedefs/load-file.js:13:9)
    at async /opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/load/cjs/load-typedefs/collect-sources.js:200:25
Error generating diff

GraphQL Metadata Schema Changes

GraphQL Metadata Schema Changes

[error] Error: Unable to read JSON file: /home/runner/work/twenty/twenty/main-metadata-schema-introspection.json: Not valid JSON content
at JsonFileLoader.handleFileContent (/opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/json-file-loader/cjs/index.js:147:19)
at /opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/json-file-loader/cjs/index.js:95:43
at async Promise.all (index 0)
at async JsonFileLoader.load (/opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/json-file-loader/cjs/index.js:88:9)
at async /opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/load/cjs/load-typedefs/load-file.js:15:39
at async Promise.all (index 4)
at async loadFile (/opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/load/cjs/load-typedefs/load-file.js:13:9)
at async /opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/load/cjs/load-typedefs/collect-sources.js:200:25
Error: Unable to read JSON file: /home/runner/work/twenty/twenty/main-metadata-schema-introspection.json: Not valid JSON content
at JsonFileLoader.handleFileContent (/opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/json-file-loader/cjs/index.js:147:19)
at /opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/json-file-loader/cjs/index.js:95:43
at async Promise.all (index 0)
at async JsonFileLoader.load (/opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/json-file-loader/cjs/index.js:88:9)
at async /opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/load/cjs/load-typedefs/load-file.js:15:39
at async Promise.all (index 4)
at async loadFile (/opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/load/cjs/load-typedefs/load-file.js:13:9)
at async /opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/load/cjs/load-typedefs/collect-sources.js:200:25
⚠️ Breaking changes or errors detected in GraphQL metadata schema

[error] Error: Unable to read JSON file: /home/runner/work/twenty/twenty/main-metadata-schema-introspection.json: Not valid JSON content
    at JsonFileLoader.handleFileContent (/opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/json-file-loader/cjs/index.js:147:19)
    at /opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/json-file-loader/cjs/index.js:95:43
    at async Promise.all (index 0)
    at async JsonFileLoader.load (/opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/json-file-loader/cjs/index.js:88:9)
    at async /opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/load/cjs/load-typedefs/load-file.js:15:39
    at async Promise.all (index 4)
    at async loadFile (/opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/load/cjs/load-typedefs/load-file.js:13:9)
    at async /opt/hostedtoolcache/node/24.11.1/x64/lib/node_modules/@graphql-inspector/cli/node_modules/@graphql-tools/load/cjs/load-typedefs/collect-sources.js:200:25
Error generating diff

REST API Analysis Error

⚠️ Error occurred while analyzing REST API changes

Error Output

REST Metadata API Analysis Error

⚠️ Error occurred while analyzing REST Metadata API changes

Error Output

⚠️ Please review these API changes carefully before merging.

⚠️ Breaking Change Protocol

Breaking changes detected but PR title does not contain "breaking" - CI will pass but action needed.

🔄 Options:

  1. If this IS a breaking change: Add "breaking" to your PR title and add BREAKING CHANGE: to your commit message
  2. If this is NOT a breaking change: The API diff tool may have false positives - please review carefully

For breaking changes, add to commit message:

feat: add new API endpoint

BREAKING CHANGE: removed deprecated field from User schema

@FelixMalfait FelixMalfait merged commit 04c5968 into main Dec 16, 2025
58 of 60 checks passed
@FelixMalfait FelixMalfait deleted the feat/enforce-user-friendly-exception-messages branch December 16, 2025 13:44
@twenty-eng-sync
Copy link
Copy Markdown

Hey @FelixMalfait! After you've done the QA of your Pull Request, you can mark it as done here. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant