There's an Exception for That

There's an Exception for That

"Stack level too deep?", I asked myself, perplexed. All I did was add a gem and a few lines of initialization code.

The gem that I added was a client for a configuration service. For fun, let's call this configuration service "caas" for Configuration as a Service. Values can be added to it via migrations, which work similarly to ActiveRecord migrations. Any pending migrations are run at deploy.

I wrote some test migrations and ran them successfully in my local development environment. Deployment to QA, however, failed. Let's replicate that failure locally by setting RACK_ENV to qa and running the migration Rake task.

$ bundle exec rake caas:migrate RACK_ENV=qa
rake aborted!
stack level too deep
Tasks: TOP => caas:migrate
(See full trace by running task with --trace)

OK. Let's run with --trace.

$ bundle exec rake --trace caas:migrate RACK_ENV=qa
** Invoke caas:migrate (first_time)
** Invoke caas:environment (first_time)
** Execute caas:environment
** Execute caas:migrate
rake aborted!
stack level too deep
/Users/cdemyanovich/.rbenv/versions/1.9.3-p484/lib/ruby/1.9.1/rake/task.rb:162
Tasks: TOP => caas:migrateshell

Not much help. I already knew that there was a problem running the migrations. At this point, my teammates and I spent quite some time thinking about the failure and reading code. Then it hit me: even though there's no backtrace, there must be an exception associated with the "stack level too deep" message. Some searching turned up an answer: SystemStackError.

I temporarily changed the client gem to rescue SystemStackError, updated the host application Gemfile to refer to a local copy of the gem, and ran the migrations again.

$ bundle exec rake --trace caas:migrate RACK_ENV=qa
** Invoke caas:migrate (first_time)
** Invoke caas:environment (first_time)
** Execute caas:environment
** Execute caas:migrate
stack level too deep
/Users/cdemyanovich/source/configuration_client/lib/configuration_client/patches/net_http_timeout.rb:8
rake aborted!
Tasks: TOP => caas:migrate

Perfect. Now we know exactly where the problem is.

If you encounter a problem and have nothing but an error message to go on, determine whether it comes from an exception that you can rescue, even if only temporarily. Speculation and intuition are useful, but a backtrace will tell you exactly where you need to look.