ruby-grape/grape · warning
Returning or throwing a Hash from a rescue handler is deprec
Error message
Returning or throwing a Hash from a rescue handler is deprecated. Use `error!(...)` or a `Grape::Exceptions::ErrorResponse` instead.
What it means
A `rescue_from` handler used to be allowed to return (or throw) a Hash of `{ message:, status:, headers: }`, which Grape converted into a rack response. That contract is deprecated: `error?` detects exactly that three-key Hash, warns via `Grape.deprecator`, and directs you to `error!` or a `Grape::Exceptions::ErrorResponse`. Note that a Hash missing any of the three keys is not treated as an error response at all — it becomes the response body verbatim.
Source
Thrown at lib/grape/middleware/error.rb:220
end
def error!(message, status = default_status, headers = {}, backtrace = [], original_exception = nil)
env[Grape::Env::API_ENDPOINT].status(status) # not error! inside route
merged_headers = { Rack::CONTENT_TYPE => content_type }.merge!(headers)
error = Grape::Exceptions::ErrorResponse.new(
status:, message:, headers: merged_headers, backtrace:, original_exception:
)
rack_response(status, merged_headers, format_message(error))
end
def error?(response)
case response
when Grape::Exceptions::ErrorResponse
true
when Hash
return false unless response.key?(:message) && response.key?(:status) && response.key?(:headers)
Grape.deprecator.warn(
'Returning or throwing a Hash from a rescue handler is deprecated. ' \
'Use `error!(...)` or a `Grape::Exceptions::ErrorResponse` instead.'
)
true
else
false
end
end
end
end
end
View on GitHub (pinned to 22d7975629)
Solutions
- Call `error!('missing', 404)` inside the handler and let Grape build the response
- Or construct the structured object: `throw :error, Grape::Exceptions::ErrorResponse.new(message: 'missing', status: 404, headers: {})`
- Audit handlers during upgrade with `Grape.deprecator.behavior = :raise`
Example fix
# before
rescue_from NotFoundError do |e|
{ message: 'not found', status: 404, headers: {} }
end
# after
rescue_from NotFoundError do |e|
error!('not found', 404)
end Defensive patterns
Strategy: validation
Validate before calling
# CI guard: hash-returning rescue handlers raise in the test env Grape.deprecator.behavior = :raise if Rails.env.test?
Try / catch
# In request specs, assert on the rendered error instead of the handler's return value:
# expect { get '/missing' }.to change { response.status }.to(404)
# — this fails loudly if a handler still returns a Hash Prevention
- Make every rescue_from handler end in `error!` or a thrown `Grape::Exceptions::ErrorResponse`
- Request-spec each rescued endpoint so a Hash-shaped return value never passes silently
- Do not port Sinatra hash-return error blocks; rewrite them with `error!` during the Grape migration
When it happens
Trigger: `rescue_from NotFoundError do |e| { message: 'missing', status: 404, headers: {} } end`; throwing the Hash: `throw :error, { message: ..., status: ..., headers: ... }` from a handler or custom middleware.
Common situations: Apps written against very old Grape; upgrading across this deprecation; handlers shared with Sinatra-style code that return hashes.
Related errors
- rescue_from #{meta_selector.inspect} does not accept additio
- `#{self.class.name}#[]` is deprecated. Use the named accesso
- Grape: rescue_from #{klass} will never run — #{covered_by} w
- both :with option and block cannot be passed
- with: #{with.class}, expected Symbol, String or Proc
AI-assisted analysis of ruby-grape/grape@22d7975629 (2026-08-21).
Data as JSON: /api/errors/662fc1dd1648151a.
Report an issue: GitHub.