Ideally I wrap the test step in a error handling mechanism that either throws the error and kills the test or it proceeds to the next step even if it fails. The test log records the failure, but the rest of the steps get executed so that the other functionality can be tested too. The step then passes a true/false depending on the nature of the step which would then either fail over and kill the test or move on to the next step anyway.
From a code standpoint it won't be able to determine if it's a serious error or a minimal one so you have to put some intelligence in the test step to go along with it in order to determine if you can continue should the assertion fail or if you need to stop all together. From a coding standpoint if it fails it's dead regardless of the failure.
In general Selenium is executed on a Unit Test framework which would make any error a failure unless that is the actual goal. If it's c# you can catch everything generically and then spit out the exact text, with java you have to catch the unique errors that are possible.
I often throw a unique error with specific text based on the framework itself when someone doesn't utilize the framework properly, but that is totally up to the automation developer. If you utilize custom errors be very consistent and consider creating an error framework so that it's universal and easy to trace back to the source issue that triggered the error.