Raise better Exceptions

We use Python extensively at work, and our web application talks to a PostgreSQL database using the SQLAlchemy database toolkit.

One evening last week, I received an alert from Sentry about some database connections timing out.

DatabaseError: (psycopg2.DatabaseError) SSL SYSCALL error: Connection timed out
 [SQL: 'SELECT pg_advisory_lock(%(key)s)'] [parameters: {'key': 68197969}]
 (Background on this error at: http://sqlalche.me/e/4xp6)

The first two lines of the exception tells you what happened. But the interesting bit is the next line.

 (Background on this error at: http://sqlalche.me/e/4xp6)

Not only did the library tell me what happened. But it also told me what the background on this error is, and what a possible fix could look like.

This is very cool.

As a developer, my first instinct when I run into an exception which I'm clueless about, is to basically copy paste the error into Google and see what comes up. If you're lucky, you'll probably find a StackOverflow thread that talks about exactly the same problem. And if you're even luckier, that thread might even have an accepted solution.

Often times though, you're not so lucky, and the situation is best described by the following XKCD.

In such a situation, the only other alterantive is to read the source code and try to figure things out. Depending on the code quality, this may or may not be a pleasant experience, but that's for another blog post.

If you're writing a library that's being used by other people, take a moment to think about the exceptions that it can raise, the different reasons why those exceptions come into picture, and what a possible fix could be. Or if you don't want to go to those lengths, then at least raise relevant exceptions. Don't be the lazy dev who writes raise Exception(). Replace it with something more specific like raise ValueError('Expected integers'). Your users would thank you.