I know about 'always in DML operations'. But for what? What do we get? The code will crash anyway, and we can find the error in logs even without this construction. What's the main point of try/catch
? And what exactly can we do in catch
except System.debug()
or sending email alert with an error message? I would be grateful for the answers with examples.
[SalesForce] When do we really need try/catch
Related Solutions
The try-catch will create a new varaible in the scope of the current run time, and this will happen every time the catch clause is executed. Now this variable does not exist anywhere else in other parts of the script or even in the same scope.
The variable is created and destroyed at the runtime, this is a unique case in the langauge, so with that being said some browsers may not handle it very nicely and could cause performance issues when the exceptions are caught.
In your case I don't think you will need one because one error won't stop the entire script due to the fact that it is event driven, so if something does go wrong catching the error wouldn't be beneficial
My condolences if you're reading this, because it means that you're being tortured by an extremely useless and vague error message. Let's see if we can get through this without tearing out too much hair. :-)
Deployment Error or DML Error?
If you Google "duplicate value found: <unknown>...", the results you get will cover a wide variety of root causes. The first step is to figure out which scenario is appropriate to you.
DML Error
If you're getting this error from a DML operation, you're in luck. The possible solutions seem to be more straightforward. Sometimes, there might even only be one "<unknown>" instead of two to deal with.
Here are a few of the better posts for the DML-based errors:
- Daniel Sokolowski's Blog - "Duplicate value found duplicates..."
- Developer Forums - "Exception: duplicate value found: <unknown>..."
- Developer Forums - "Duplicate value found: unknown duplicates value..."
Basically, it looks like the problem boils down to fields with unique
constraints. Daniel's blog post does a great job of breaking down the debug process.
Deployment Error
If you're getting this error while trying to deploy metadata, things are a bit tougher.
Debugging deployment errors is almost always painful in some way, but this particular error message with its two vague "<unknown>" references is especially cruel. The following steps can help to quickly get you on the right track to finding a solution.
Step One: Identify the Problem
This step is easy to start, but sometimes difficult to finish. Take a look at the error message, and I'll explain what I mean.
Error: objects/Opportunity.object(2098,13):duplicate value found: <unknown> duplicates value on record with id: <unknown>
Clearly the Opportunity object metadata I'm trying to deploy is causing a problem. Don't start Googling yet, though. There's more for you to learn about what, exactly, is failing.
Forget about the error "message" for a moment, and focus on the error location.
Error: objects/Opportunity.object(2098,13)...
The important bit here is (2098,13)
. This is the line and column number inside the Opportunity.object
metadata file where the trouble is coming from.
Here's what my file looks like near that line...
This tells me that the error seems to be specifically related to the StageName
picklist field that I'm trying to deploy.
Important: If this is EXACTLY the problem you're having, skip to the end to see a potential solution.
Step Two: Isolate the Problem
Deployments are tricky, complicated things with many dependencies to contend with. When debugging metadata errors that are not related to Apex code, simplify things by removing everything from your deployment package except the component that's giving you trouble (and its direct dependencies, of course).
If you're still getting the error after doing this, then you've successfully started the process of isolating the problem. In my case, I can try to Isolate things further by removing the entire StageName
field and re-trying my deployment.
After removing that field, my deployment finally succeeds! This conclusively proves that something I'm pushing in the StageName
field is causing the error.
Remember, this example is ONLY relevant to my situation. The metadata components that are giving you trouble will most likely have different names, be different types, etc. This is just an example.
Step Three: Start Digging
Now that I've conclusively isolated the problem to a particular field on a specific object, I can start digging deeper. Here's what I've found to be the most common possible causes.
For Picklist Fields...
If you've narrowed things down to a problem with a Picklist field, make sure that your target org does not already have an inactive picklist field with the same name as one of the ones you are trying to deploy.
If this is the case, you'll need to delete the picklist value. Once you do this, your deployment should proceed (until the next error sneaks up on you, of course).
For Other Problems...
If your problem is not related to a picklist field, the general consensus seems to be that there are some strange situations that come up if Field History Tracking is enabled on the object that is giving you trouble.
Here are the best solutions I've found related to "Field History Tracking" being a possible issue.
- DaveS (StackExchange) - "Object Deploy fails with: duplicate value found: <unknown>..."
- Michael Welburn's Blog - "Salesforce.com Metadata API Error: Duplicates Value on Record with ID"
- Known Issues In Review - "Deployment fails with duplicate value found: <unknown>..."
Conclusion
Debugging Salesforce errors is never fun. It's especially not fun when the error messages are vague, like the unhelpful "duplicate value found: <unknown>..." error message. This post has provided a framework for debugging this type of error, whether it came from a DML or a metadata deployment operation.
The steps from the "Deployment Error" section are useful for debugging other types of non-code deployment related errors. Hopefully you've found them useful. As time goes by, if additional "flavors" of this error show up, I'll update this answer to include them. Good luck out there!
Best Answer
To catch and handle an exception. The handling is the key.
What it means to handle an exception is to take an exceptional situation - something bad and out of the ordinary happened - and allow the application to safely move back into an anticipated pathway of operation, preserving
Let's look at a couple of examples.
Triggers
You're writing a trigger. The trigger takes data modified by the user, processes it, and makes updates elsewhere. It performs DML and does not use, for example,
Database.update(records, false)
, meaning that failures will throw an exception. (If you do use partial-success methods, the same principles apply, they just play out differently because errors come to you in Result objects instead of exceptions).Here, you have to answer at least two critical questions:
These questions determine how you'll respond to the exception.
If you know a particular exception can be thrown in a way that you can fix, your handler should just fix it and try again. That would be a genuine "handling" of the exception. However, in Apex, where exceptions aren't typically used as flow control, this situation is somewhat less common than in e.g. Python. That said, one example where I've personally implemented such a handler is in a
Queueable
that attempts to lock a recordFOR UPDATE
. In that situation, where I had a potential race condition to avoid, catching theQueryException
when that query times out and simply re-enqueuing theQueueable
to try again was the right pattern.But in most cases, that's not your situation when building in Apex. It's the second question that tends to be determinant of the appropriate implementation pattern, and it's why I tend to eschew exception handlers in many cases.
The most important job your code has is not to damage the integrity of the user's data. So in most cases where an exception is related to data manipulation, I advocate for not catching it in backend code at all unless it can be meaningfully handled. Otherwise, let higher-level functionality (below) catch it, or allow the whole transaction to be rolled back to preserve data integrity.
So, again, to make this concrete: you're building a trigger whose job is to update the dollar value of an Opportunity when the user updates a related Payment. Your Opportunity update might throw a
DmlException
; what do you do?Ask the questions: Can you fix the problem in Apex alone? No. If you let the Opportunity update fail while the Payment update succeeds, do you lose data integrity? Yes.
Let the exception be raised and dealt with, or allowed to cause a rollback, at a higher level.
Non-Critical Backend Functionality
But there are other cases where you'll want to catch, log, and suppress an exception. Take for example code that sends out emails in response to data changes (I'll save for another time why I think that's a terrible pattern). Again, look to the questions above:
So here is a situation where it might make sense to wrap the sending code in a try/catch block, and log email-related exceptions using a quality logging framework. Then, don't re-raise - consume the exception and allow the transaction to continue.
You may not want to block a Case update because some User in the system has a bad email address!
User-Facing Functionality
Now, turn the page to Lightning and Visualforce. Here, you're building in the controller layer, interpreting between user input and the database.
You present a button that allows the user to perform some complex operation that can throw multiple species of exceptions. What's your handling strategy?
Here, it is much more common, and even preferable, to use broad exception handlers that don't actually handle the exception, but perform a rollback to preserve data integrity and then surface a friendly error message to the user.
For example, in Visualforce, you might do something like this:
That's friendly to the user - it shows them that the higher-level, semantic operation they attempted failed (and you might want to include the actual failure too to give them a shot at fixing it) - and it's also friendly to the database, because you make sure your handling of the exception doesn't impact data integrity.
Even better would be to be specific about the failure using multiple
catch
blocks (where applicable):In Lightning (Aura) controllers, you'll re-throw an
AuraHandledException
instead.The One Thing Not To Do
This:
There are very, very few situations where this is a good pattern. You almost never want to swallow and hide an exception, because no one is ever going to look at that log - and you'll have silent failures happening in your org, violating user trust and imbuing the system as a whole with inexplicable behavior.
If you don't need to take action on an exception, log it in a way that a user can review and act on. Never swallow it.
Think about how you'd have to answer the questions above to make this a good pattern. You'd want to swallow an exception like this when:
If those things are both the case, I suspect a design fault in the system!
This pattern also makes debugging excruciating, because your code fails silently when it should be screaming in the form of an exception.