Skip to content

Router#cascade? undefined method `[]' for nil:NilClass #1966

@delner

Description

@delner

Grape is raising an NoMethodError when implementing a really basic API endpoint.

What I expect

Basic requests to not raise errors.

What actually happens

It raises NoMethodError. Sample output from Minitest (described below):

  1) Error:
GrapeTest#test_api_success:
NoMethodError: undefined method `[]' for nil:NilClass
    /usr/local/bundle/gems/grape-1.2.5/lib/grape/router.rb:164:in `cascade?'
    /usr/local/bundle/gems/grape-1.2.5/lib/grape/router.rb:95:in `transaction'
    /usr/local/bundle/gems/grape-1.2.5/lib/grape/router.rb:72:in `identity'
    /usr/local/bundle/gems/grape-1.2.5/lib/grape/router.rb:57:in `block in call'
    /usr/local/bundle/gems/grape-1.2.5/lib/grape/router.rb:137:in `with_optimization'
    /usr/local/bundle/gems/grape-1.2.5/lib/grape/router.rb:56:in `call'
    /usr/local/bundle/gems/grape-1.2.5/lib/grape/api/instance.rb:165:in `call'
    /usr/local/bundle/gems/grape-1.2.5/lib/grape/api/instance.rb:69:in `call!'
    /usr/local/bundle/gems/grape-1.2.5/lib/grape/api/instance.rb:64:in `call'
    /usr/local/bundle/gems/grape-1.2.5/lib/grape/api.rb:66:in `call'
    /usr/local/bundle/gems/rack-test-1.1.0/lib/rack/mock_session.rb:29:in `request'
    /usr/local/bundle/gems/rack-test-1.1.0/lib/rack/test.rb:266:in `process_request'
    /usr/local/bundle/gems/rack-test-1.1.0/lib/rack/test.rb:129:in `custom_request'
    /usr/local/bundle/gems/rack-test-1.1.0/lib/rack/test.rb:58:in `get'
    /usr/local/lib/ruby/2.3.0/forwardable.rb:202:in `get'
    /app/test/contrib/grape/request_test.rb:25:in `test_api_success'

Steps to reproduce

Dependencies from Gemfile.lock

grape (1.2.5)
      activesupport
      builder
      mustermann-grape (~> 1.0.0)
      rack (>= 1.3.0)
      rack-accept
      virtus (>= 1.0.0)
rack (2.1.0)
rack-accept (0.4.5)
      rack (>= 0.4)
rack-protection (2.0.8.1)
      rack
rack-test (1.1.0)
      rack (>= 1.0, < 3)
mustermann (1.1.1)
      ruby2_keywords (~> 0.0.1)
mustermann-grape (1.0.1)
      mustermann (>= 1.0.0)
virtus (1.0.5)
      axiom-types (~> 0.1)
      coercible (~> 1.0)
      descendants_tracker (~> 0.0, >= 0.0.3)
      equalizer (~> 0.0, >= 0.0.9)

Minitest:

require 'rack/test'
require 'grape'

class TestingAPI < Grape::API
  namespace :base do
    desc 'Returns a success message'
    get :success do
      'OK'
    end
  end
end

class GrapeTest < MiniTest::Test
  include Rack::Test::Methods

  def app
    TestingAPI
  end

  def test_api_success
    get '/base/success'
    assert last_response.ok?
    assert_equal('OK', last_response.body)
  end
end

Other thoughts

This did happen after updating my Gemfile.lock, which showed the following being updated:

Installing ruby2_keywords 0.0.2
Installing mustermann 1.1.1
Installing mustermann-grape 1.0.1

Between looking at the changes in those repos and the stacktrace, I didn't see anything that would explain it.

Digging deeper into the Grape code, what I found in middleware/base.rb was:

begin
  @app_response = @app.call(@env)
ensure
  begin
    after_response = after
  rescue StandardError => e
    warn "caught error of type #{e.class} in after callback inside #{self.class.name} : #{e.message}"
    raise e
  end
end

response = after_response || @app_response

Running this through my test, @app_response was [200, {}, ["OK"]], and after_response was derived from ["/usr/local/bundle/gems/grape-1.2.5/lib/grape/middleware/formatter.rb", 21] which returned:

#<Rack::Response:0x0000561ee6ee7a40
 @block=nil,
 @body=["OK"],
 @buffered=false,
 @header={"Content-Type"=>"text/plain"},
 @length=0,
 @status=200,
 @writer=#<Method: Rack::Response(Rack::Response::Helpers)#append>>

So it would select after_response which would return #<Rack::Response> to rack/head.rb which parsed it into an Array as [#<Rack::Response>, nil nil].

This Array is then eventually passed to Router#cascade? where it would fail because the second argument is nil:

def cascade?(response)
  response && response[1][Grape::Http::Headers::X_CASCADE] == 'pass'
end

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions