Rollbar で Rack::QueryParser::InvalidParameterError が通知されるのを抑止する

Rails のエラーを捕捉するのに Rollbar を使っている場合、次のような通知を受け取ることがあります。

Rack::QueryParser::InvalidParameterError: invalid byte sequence in UTF-8

ArgumentError: invalid byte sequence in UTF-8
    + 89 non-project frames
Rack::QueryParser::InvalidParameterError: invalid byte sequence in UTF-8
    + 87 non-project frames
ArgumentError: invalid byte sequence in UTF-8
    + 85 non-project frames
Rack::QueryParser::InvalidParameterError: invalid byte sequence in UTF-8
    + 83 non-project frames

大抵の場合、このエラーは middleware レイヤーで起きるエラーであり、Rails では Rack::QueryParser::InvalidParameterError (= Rack::Utils::InvalidParameterError) を rescue して 400 を返すようになっています。
cf. https://github.com/rails/rails/commit/d59a24d543b4fd34d453e8209caae5fef315ea78

よって、特別な事情がない限りは config/initializers/rollbar.rb に次の 1 行を追加すると良いです。

config.exception_level_filters.merge!('Rack::QueryParser::InvalidParameterError' => 'ignore')

本題は以上です。以下、調べたことについてつらつら。

Rack::QueryParser::InvalidParameterError の歴史

Rack は application/x-www-form-urlencoded のパラメータのキーに UTF-8 として不正なシーケンスが存在すると、params を参照した時に例外を投げるという問題が随分前からあります。
cf. ArgumentError: invalid byte sequence in UTF-8 · Issue #673 · rack/rack

次のようなログを見たことがある人も多いのではないでしょうか。

Rack::QueryParser::InvalidParameterError (invalid byte sequence in UTF-8):

rack (2.0.5) lib/rack/query_parser.rb:72:in `rescue in parse_nested_query'
rack (2.0.5) lib/rack/query_parser.rb:60:in `parse_nested_query'
rack (2.0.5) lib/rack/request.rb:468:in `parse_query'
rack (2.0.5) lib/rack/request.rb:343:in `POST'
actionpack (5.2.1) lib/action_dispatch/http/request.rb:382:in `block (2 levels) in POST'
actionpack (5.2.1) lib/action_dispatch/http/parameters.rb:109:in `block in parse_formatted_parameters'
actionpack (5.2.1) lib/action_dispatch/http/parameters.rb:109:in `fetch'
actionpack (5.2.1) lib/action_dispatch/http/parameters.rb:109:in `parse_formatted_parameters'
actionpack (5.2.1) lib/action_dispatch/http/request.rb:381:in `block in POST'
rack (2.0.5) lib/rack/request.rb:57:in `fetch'
rack (2.0.5) lib/rack/request.rb:57:in `fetch_header'
actionpack (5.2.1) lib/action_dispatch/http/request.rb:380:in `POST'
actionpack (5.2.1) lib/action_dispatch/http/parameters.rb:55:in `parameters'
actionpack (5.2.1) lib/action_dispatch/http/filter_parameters.rb:43:in `filtered_parameters'
actionpack (5.2.1) lib/action_controller/metal/instrumentation.rb:23:in `process_action'
actionpack (5.2.1) lib/action_controller/metal/params_wrapper.rb:256:in `process_action'
activerecord (5.2.1) lib/active_record/railties/controller_runtime.rb:24:in `process_action'
actionpack (5.2.1) lib/abstract_controller/base.rb:134:in `process'
actionview (5.2.1) lib/action_view/rendering.rb:32:in `process'
(snip)

似たような問題として、不正なパーセントエンコーディングのパラメータが送られてくると例外を投げるという問題もあります。

cf. invalid %-encoding error in application for malformed uri · Issue #337 · rack/rack

いずれも「そのようなリクエストに対処するのは Rack の責務じゃない」というスタンスを貫いているので、Rack 側で何らかの対応が入ることはないでしょう。

そこで導入されたのが Rack::Utils::InvalidParameterError です。
cf. Raise specific exception if the parameters are invalid by rafaelfranca · Pull Request #713 · rack/rack

Rails では 4.2 からこのエラーを rescue して 400 を返すようになりました。
cf. https://github.com/rails/rails/commit/d59a24d543b4fd34d453e8209caae5fef315ea78

なお、Rack::QueryParser::InvalidParameterErrorRack::Utils::InvalidParameterError同じものです。

最終的に rescue されるエラーがどうして Rollbar に捕捉されるのか?

Rails 5.2 の場合、middleware stack は次のようになっています。

use Rack::Sendfile
use ActionDispatch::Static
use ActionDispatch::Executor
use ActiveSupport::Cache::Strategy::LocalCache::Middleware
use Rack::Runtime
use Rack::MethodOverride
use ActionDispatch::RequestId
use ActionDispatch::RemoteIp
use Sprockets::Rails::QuietAssets
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use WebConsole::Middleware
use ActionDispatch::DebugExceptions
use ActionDispatch::Reloader
use ActionDispatch::Callbacks
use ActiveRecord::Migration::CheckPending
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use ActionDispatch::ContentSecurityPolicy::Middleware
use Rack::Head
use Rack::ConditionalGet
use Rack::ETag
use Rack::TempfileReaper
run MyApp::Application.routes

cf. https://guides.rubyonrails.org/rails_on_rack.html#inspecting-middleware-stack

これに対し、Rollbar は ActionDispatch::DebugExceptions の後に Rollbar::Middleware::Rails::RollbarMiddleware を挿入します
よって、ActionDispatch::DebugExceptions より後に起きた例外を捕捉して通知できるようになるわけです。
cf. https://github.com/rollbar/rollbar-gem/blob/v2.8.0/lib/rollbar/middleware/rails/rollbar.rb#L31-L34

Rack::Utils::InvalidParameterError を rescue しているのは ActiveSupport::Cache::Strategy::LocalCache::Middleware で、Rollbar::Middleware::Rails::RollbarMiddleware より前の middleware なので、最終的に rescue されるエラーも通知されることになります。

広告
tmux で列数固定で window を分割して複数サーバに SSH する upstart で start した job の設定を変更するには一度 stop する必要がある