better_errors: NoMethodError at /__better_errors/xxxx/variables undefined method `id' for nil:NilClass

when I use better_errors work with Sinatra + Grape, it not works

my code is:

# configure.rb file
class Configure < Sinatra::Base
  configure :development do
    use BetterErrors::Middleware
    BetterErrors.application_root = __dir__
  end
end
# dashboard.rb file
class Dashboard < Sinatra::Base
  use Configure

  get('/') { raise }
end
# apiv1.rb file
class APIv1 < Grape::API
  format :json

  resource do
    get :test do
      raise
    end
  end

end
# config.ru file
require 'sinatra'
require 'grape'
require 'better_errors'

class Admin < Sinatra::Base
  use Dashboard
end

class API < Grape::API
  use BetterErrors::Middleware
  mount APIv1 => '/api/v1'
end

run Rack::Cascade.new [API, Admin]

when i visit: http://0.0.0.0:9292/api/v1/test first APIv1 class raise an error, it works, the left is ok, but when i click a left section, the right deteils not work.

and then visit: http://0.0.0.0:9292 Dashboard class raise an error, it works, the left list and right details is ok.

it has an error, the details is:

NoMethodError at /__better_errors/0e1adbe07252ede1/variables
undefined method `id' for nil:NilClass
file: middleware.rb location: internal_call line: 127

and i view the code, and found:

    def internal_call(env, opts)
      if opts[:id] != @error_page.id
        return [200, { "Content-Type" => "text/plain; charset=utf-8" }, [JSON.dump(error: "Session expired")]]
      end

      env["rack.input"].rewind
      response = @error_page.send("do_#{opts[:method]}", JSON.parse(env["rack.input"].read))
      [200, { "Content-Type" => "text/plain; charset=utf-8" }, [JSON.dump(response)]]
    end

the @error_page is nil

and the second, when i first visit: http://0.0.0.0:9292 and then visit http://0.0.0.0:9292/api/v1/test

the error not occur any more, it just return an json: {“error”:“Session expired”}

please help

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Comments: 23 (1 by maintainers)

Most upvoted comments

I’ve figured it out, at least for my case: a new BetterErrors::Middleware instance is being created for every request. This means @error_page will be nil for any subsequent internal_call. The quick ‘n’ dirty solution is to instantiate a single instance and reuse it across all requests.

Here’s how I did it:

class BetterErrors::Middleware::Proxy
  @@middleware = BetterErrors::Middleware.new {|env| @@app.call(env)}
  def initialize(app); @@app = app; end
  def call(env); @@middleware.call(env); end
end

Hope it helps!