• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ruby-grape / grape / 32037970029 / 27
97%
master: 100%

Build:
Build:
LAST BUILD BRANCH: feature/strict-params
DEFAULT BRANCH: master
Ran 17 Aug 2026 02:19PM UTC
Files 168
Run time 6s
Badge
Embed ▾
README BADGES
x

If you need to use a raster PNG badge, change the '.svg' to '.png' in the link

Markdown

Textile

RDoc

HTML

Rst

17 Aug 2026 02:08PM UTC coverage: 95.614% (-0.004%) from 95.618%
32037970029.27

push

github

ericproulx
Answer 500 when an error response cannot be rendered

Grape::Middleware::Error#call! renders the error response from inside its own
rescue clause, so that clause never covered the rendering. An error formatter
that raised on the payload it was handed took the exception straight out
through every middleware above Grape and into the application server —
`rescue_from :all` did not help, because the failure happened after the
handler had already returned.

A rescue_from handler echoing request-derived bytes was enough to hit it:

    rescue_from(Missing) { |e| error!({ detail: e.message }, 404) }

with an invalid UTF-8 byte in the path, the JSON formatter raised
JSON::GeneratorError and the request died rather than being answered.

Guard the rendering in error_response. On failure, first retry the API's own
format with the framework's InternalServerError, whose message is a static
string and so cannot be what defeated the first attempt; if that fails too — a
formatter broken outright rather than one payload it choked on — answer
without a formatter at all. Both attempts call format_message directly instead
of re-entering error_response, so the fallback cannot recurse. This is the
shape ActionDispatch::ShowExceptions#render_exception already has in Rails,
down to the text/plain last resort.

The guard sits on the rendering rather than around run_rescue_handler on
purpose. Wrapping the handler call too would have swallowed things that must
keep propagating, the deprecation raised when a handler returns a Hash among
them.

Exceptions that no rescue_from matches still propagate unchanged; only
rendering failures are caught.

Swallowing an exception must not make it invisible. Grape put the exception on
env['grape.exception'], but that is a Grape-private key no tracker reads, so a
rendering failure that Sentry used to report as a raised exception would have
become an unremarkable 500. Publish it on env['rack.exception'] as well — the
convention for an exceptio... (continued)

1189 of 1305 branches covered (91.11%)

Branch coverage included in aggregate %.

3803 of 3916 relevant lines covered (97.11%)

1120.85 hits per line

Source Files on job run-3.3-gemfiles/rails_8_0.gemfile - 32037970029.27
  • Tree
  • List 168
  • Changed 2
  • Source Changed 2
  • Coverage Changed 2
Coverage ∆ File Lines Relevant Covered Missed Hits/Line Branch Hits Branch Misses
  • Back to Build 32037970029
  • e0bd7785 on github
  • Prev Job for on fix/error-rendering-failsafe (#31997173157.19)
  • Next Job for on fix/error-rendering-failsafe (#32044609601.24)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc