Last Updated: February 25, 2016
·
656
· jtai

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.

This tip was reposted from my blog, jontai.me