Skip to main content

Title: Handling Errors Like a Pro: Sending Original Errors to Sentry While Keeping Client Responses Clean

I recently ran into a challenge with error handling in my NestJS project. It’s a common scenario: you want to simplify errors for the client but still capture the original, raw error for debugging and monitoring purposes in Sentry. The problem? My current approach was sending the simplified error to Sentry, not the actual, unprocessed error. Here’s how I solved it.


My Story: A Misstep in Error Handling

I was working on the create function of my NestJS service, responsible for creating a new collection company. Everything was fine until I realized that while I was throwing clean, client-friendly error messages using HttpException, I wasn’t logging the full, raw error in Sentry.

For example, my code looked something like this:

throw new HttpException(errorMessage, errorStatus);

Sure, my errorConvertor function transformed complex errors into simplified errorMessage and errorStatus for the client, but Sentry was capturing these processed errors instead of the original error. When debugging, this was less than helpful.

I needed to send the raw error to Sentry while still keeping my responses clean for the clients. Here’s what I did.


The Solution: Separating Error Logging and Client Responses

I realized I could solve this by explicitly logging the raw error to Sentry before transforming it. Here’s how I updated my code:

Updated create Function

async create(createCollectionCompanyDto: CreateCollectionCompanyDto) {
try {
const res = await this.collectionCompanyModel.create(createCollectionCompanyDto);
return res;
} catch (err) {
// Log the raw error to Sentry
Sentry.captureException(err);

// Simplify the error for the client
const { errorMessage, errorStatus } = errorConvertor(err);

// Throw the simplified error for the client
throw new HttpException(errorMessage, errorStatus);
}
}

Why This Works

  1. Capturing the Original Error:
    By calling Sentry.captureException(err) directly inside the catch block, I ensure that the original error, with all its valuable debugging information (stack trace, error type, etc.), is logged to Sentry.
  2. Client-Friendly Responses:
    Using errorConvertor, I process the raw error into a clean and understandable format for the client. This keeps the client-side experience polished and professional.
  3. Separation of Concerns:
    This approach separates error logging from client communication, ensuring that both tasks are handled independently and effectively.

Refining the Sentry Filter (Optional Improvement)

For projects where errors are also globally handled in a custom exception filter, you can further enhance the SentryFilter to accommodate both raw and transformed errors. Here’s an example:

@Catch()
export class SentryFilter extends BaseExceptionFilter {
catch(exception: HttpException | Error, host: ArgumentsHost) {
// Log additional details to Sentry
if (exception instanceof HttpException) {
const response = exception.getResponse();
const status = exception.getStatus();
Sentry.captureException({
message: exception.message,
statusCode: status,
context: response,
});
} else {
Sentry.captureException(exception);
}
super.catch(exception, host);
}
}

This ensures that any error caught by the global filter — whether it’s raw or transformed — gets properly logged in Sentry with all relevant context.


My Takeaway

The key lesson here is that error handling is not a one-size-fits-all approach. While you want your users to see simplified, helpful error messages, your backend should log every detail to give you the tools to debug effectively.


How This Changed My Workflow

After implementing this, I immediately saw the benefits. Debugging became significantly easier because I had access to the raw error details in Sentry. At the same time, my clients continued to see clean, user-friendly error messages.

This approach has now become a best practice for me, and I hope it helps you as much as it helped me.


Final Thoughts

If you’ve ever struggled with balancing client-friendly error responses and detailed logging for debugging, this is the way to go. By separating logging and responses, you get the best of both worlds: happy clients and a happy dev team.

Happy coding! ๐Ÿš€

    Popular posts from this blog

    Xcode and iOS Version Mismatch: Troubleshooting "Incompatible Build Number" Errors

    Have you ever encountered a frustrating error while trying to run your iOS app in Xcode, leaving you scratching your head? A common issue arises when your device's iOS version is too new for the Xcode version you're using. This often manifests as an "incompatible build number" error, and looks like this: DVTDeviceOperation: Encountered a build number "" that is incompatible with DVTBuildVersion. This usually happens when you are testing with beta versions of either iOS or Xcode, and can prevent Xcode from properly compiling your storyboards. Let's explore why this occurs and what you can do to resolve it. Why This Error Occurs The core problem lies in the mismatch between the iOS version on your test device and the Software Development Kit (SDK) supported by your Xcode installation. Xcode uses the SDK to understand how to build and run apps for specific iOS versions. When your device runs a newer iOS version than Xcode anticipates, Xcode mi...

    How to Fix the “Invariant Violation: TurboModuleRegistry.getEnforcing(…): ‘RNCWebView’ Could Not Be Found” Error in React Native

    When working with React Native, especially when integrating additional libraries like react-native-signature-canvas , encountering errors can be frustrating. One such error is: Invariant Violation: TurboModuleRegistry. getEnforcing (...): 'RNCWebView' could not be found This error often occurs when the necessary dependencies for a module are not properly linked or when the environment you’re using doesn’t support the required native modules. Here’s a breakdown of how I encountered and resolved this issue. The Problem I was working on a React Native project where I needed to add the react-native-signature-canvas library to capture user signatures. The installation process seemed straightforward: Installed the package: npm install react-native-signature- canvas 2. Since react-native-signature-canvas depends on react-native-webview , I also installed the WebView package: npm install react- native -webview 3. I navigated to the iOS directory and ran: cd ios pod install Everythi...

    Fixing FirebaseMessagingError: Requested entity was not found.

    If you’re working with Firebase Cloud Messaging (FCM) and encounter the error: FirebaseMessagingError: Requested entity was not found. with the error code: messaging/registration-token-not-registered this means that the FCM registration token is invalid, expired, or unregistered . This issue can prevent push notifications from being delivered to users. ๐Ÿ” Possible Causes & Solutions 1️⃣ Invalid or Expired FCM Token FCM tokens are not permanent and may expire over time. If you’re storing tokens in your database, some might be outdated. ✅ Solution: Remove invalid tokens from your database when sending push notifications. Refresh and store the latest FCM token when the app starts. Example: Automatically Refresh Token firebase. messaging (). onTokenRefresh ( ( newToken ) => { // Send newToken to your backend and update the stored token }); 2️⃣ Token Unregistered on Client Device A token might become unregistered if: The app is uninstalled on the user’s device. ...