1

Say your making a library Foo that depends on a 3rd-party library Bar.

Bar throws a custom exception \OtherVendor\Bar\CustomException.

Is it recommended to just throw that exact exception to your clients (devs using your lib) or should you catch it then convert it to your own exception? E.g.,

try {
    $bar->stuff();
} catch (\OtherVendor\Bar\CustomException $ex) {
    throw new \MyLib\Foo\MyCustomException();
}

To explain further, is it better for your clients to know about that 3rd-party exception in your documentation? e.g.,

You can catch \OtherVendor\Bar\CustomException in case of x...

or should you "rebrand" the exception so clients don't need to deal with another lib's namespace? E.g.,

You can catch \MyLub\Foo\MyCustomException in case of x...

  • If someone received the third party exception; would they need to change your code to fix the problem or theirs? – TZHX Feb 16 at 11:17
  • @TZHX Not sure if this is a rhetorical question but what are you trying to point out? Sorry. – IMB Feb 16 at 11:24
  • Would someone receiving the third party exception, when troubleshooting, actually be able to fix the problem themselves? – TZHX Feb 16 at 11:28
  • @TZHX Yes they can do something about if they want whether they use the 3rd-party exception or the rebranded one. – IMB Feb 16 at 11:31
5

Generally speaking, it's fine to use a language's own exceptions, since these are commonly understood. I wouldn't use 3rd party exceptions, since using that 3rd party library isn't part of the API you're offering and you might swap it for another 3rd party library (or remove it altogether) in future versions. If a client of your library built some of their error handling based on the 3rd party exception, they will have to rewrite their code. By using your own exception ('rebranding it', as you call it), you'll have the option of keeping the interface identical to previous versions.

(disclaimer: I use PHP only very sparingly, this recommendation is based on experience with half a dozen other languages)

  • Whether or not they use mine or the 3rd-party exception, a non-backwards compatible version will break it anyway so the swapping/removing won't be a big deal since it will be versioned. Thing is, this 3rd-party exception makes perfect sense due the the precision of the exception, a general/built-in exception is not suitable in this particular case. – IMB Feb 16 at 11:29
  • By using your own exception, you'll have the option of keeping the interface identical to previous versions. – Glorfindel Feb 16 at 11:31
  • So I guess what you're saying it's better to rebrand it. – IMB Feb 16 at 11:32
  • Yes, that is my opinion. – Glorfindel Feb 16 at 11:33
3

TL;DR: It's a waste of time to rebrand exceptions, in at least 99 percent of all situations.

A valuable rule of thumb is to catch exceptions only:

  • At application top level (telling the end user about the failure) or
  • At places where you know and implement a strategy how to achieve your overall goal even in that specific failure case. In other words: if you receive an exception you don't fully understand, and don't have a generic "retry" or a "try-a-different-way" strategy, don't catch! Let your caller deal with the situation that his call failed.

Both valid cases don't apply to you, but maybe to your caller. You're designing a library, not a top-level application. Your code shows that you don't want to recover from the exception (retrying or whatever), but just tell your caller about it.

So the main question about your API design is "Will rebranding the exception make it easier for your caller to decide about and implement an error-recovery strategy?"

There are a few situations to be considered now:

  • Most probably your caller doesn't want to implement any recovery strategies, but just report an error to the user and restart from top level. In that case, the exception type doesn't matter at all.

  • Maybe your caller seriously needs your API call to succeed, so he's ready to retry it a few times in case of failure. He'll write a retry-loop around your API call, and the only aspect where your rebranded exception can help him, is if it reliably tells him that retries won't change the outcome of your call. This "help" only shortens the time until he gives up...

  • Maybe your caller has an alternative way of reaching his goal instead of your library call (that's a very rare situation). Then he'll most probably do that if he gets an exception, no matter what type of exception that is.

So in general, to your caller's program flow it doesn't matter what type of exception he gets.

But there's the error message to be presented to the user, and the information to be written into some kind of log.

  • If your rebranded exception can provide a description that's presentable to the user, it might be worth the effort. Of course, you have to document that fact with your exception, otherwise your caller will create his own messages anyway. And hopefully you know enough about the end user's problem domain and native language so you can really supply a useful message. Considering that, you most probably won't be able to supply a useful message.
  • Make sure your rebranded exception contains all information relevant for a technical analysis of the problem, esp. the complete stack trace. So, if you create a rebranded exception, make sure to include the original one as its "previous". And maybe you have some context information you'd like to add to the logged problem description, then "rebrand" the exception and add the context to the message.

So, there are very few situations where I see a benefit in rebranding an exception.

  • 1
    Not one thought about providing a stable API for Foo, independent of the specific 3rd party lib? – Doc Brown Feb 16 at 16:45
  • @DocBrown My exception declaration for the API would be: Method can throw any exception, don't try to make any decisions based on the exception type. – Ralf Kleberhoff Feb 16 at 17:18
  • That means the API call which involve 3rd partx calls should all have the contract "can thow any exceptiojs of any type. – Doc Brown Feb 16 at 22:48
  • 1
    Even in the case of retrying, this might not even be done at top level so the lower level could simply be forwarding the exception to the top level after too many failures, and we’re back to point 1. – Steve Chamaillard Feb 17 at 9:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.