Using Scalatra’s halt() in a try/catch Block
Between Scala’s Option
and lift’s Box
(I use lift-mongorecord with Scalatra), I rarely use try {...} catch {...}
in Scala. But on one occasion, I did end up using it to handle any problems that might come up while talking to an external service.
try {
// call external service
} catch {
case e => halt(500, e.getMessage)
}
Things worked fine at first. Later, I needed to add an authorization check in the try {...}
block, which did a halt()
if the check failed.
try {
// call external service
if (!authorized) {
halt(401, "Authorization required")
}
} catch {
case e => halt(500, e.getMessage)
}
To my surprise, my app returned a 500 instead of the expected 401 if the external service returned something that failed the authorization check. After puzzling over it a bit, I remembered reading that Scalatra’s halt()
works by throwing an exception under the hood. (Actually it throws a subclass of Throwable
, more on that in a bit.) When the inner halt()
is called, the 401 is caught by the catch {...}
block and converted into a 500.
To make this work, I would have to alter my blanket catch
to look for whatever halt()
throws and let that bubble up. But what does halt()
throw? As it turns out, halt()
throws a Throwable
, which is the superclass of Exception
. As noted in this post, only subclasses of Exception
should be handled in the catch {...}
block, which allows the inner halt()
‘s Throwable
to bubble up.
try {
// call external service
if (!authorized) {
halt(401, "Authorization required")
}
} catch {
// only handle subclasses of Exception
case e:Exception => halt(500, e.getMessage)
}
For those of you that are curious, halt()
actually throws a HaltException
which extends ControlThrowable
.