rails/rails · warning · ActionDispatch::TestHelpers::PageDumpHelper::InvalidResponse

Response is a redirection!

Error message

Response is a redirection!

What it means

Raised as ActionDispatch::TestHelpers::PageDumpHelper::InvalidResponse from save_page (the private engine behind save_and_open_page) when response.redirection? is true. The helper writes response.body to an HTML file to open in a browser, but a 3xx redirect has an empty/Location-only body unsuitable for inspection, so it refuses rather than write a misleading dump.

Source

Thrown at actionpack/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb:16

# frozen_string_literal: true

module ActionDispatch
  module TestHelpers
    module PageDumpHelper
      class InvalidResponse < StandardError; end

      # Saves the content of response body to a file and tries to open it in your browser.
      # Launchy must be present in your Gemfile for the page to open automatically.
      def save_and_open_page(path = html_dump_default_path)
        save_page(path).tap { |s_path| open_file(s_path) }
      end

      private
        def save_page(path = html_dump_default_path)
          raise InvalidResponse.new("Response is a redirection!") if response.redirection?
          path = Pathname.new(path)
          path.dirname.mkpath
          File.write(path, response.body)
          path
        end

        def open_file(path)
          require "launchy"
          Launchy.open(path)
        rescue LoadError
          warn "File saved to #{path}.\nPlease install the launchy gem to open the file automatically."
        end

        def html_dump_default_path
          Rails.root.join("tmp/html_dump", "#{method_name}_#{DateTime.current.to_i}.html").to_s
        end
    end
  end

View on GitHub (pinned to 2c224ba8f2)

Solutions

  1. Call follow_redirect! before save_and_open_page to land on the final rendered page.
  2. If you intended a render, fix the controller (remove the redirect_to, or assert the redirect is wrong).
  3. To inspect the redirect itself, assert response.status / response.location instead of dumping the body.
  4. For multi-step flows, use the integration session's follow_redirect! repeatedly until response.redirection? is false.

Example fix

# before
post posts_path, params: { post: attrs }
save_and_open_page   # raises: response is a 302

# after
post posts_path, params: { post: attrs }
follow_redirect!
save_and_open_page   # now dumps the rendered show page
Defensive patterns

Strategy: validation

Validate before calling

# In tests, follow redirects before dumping.
def dump_after_follow
  follow_redirect! while response.redirection?
  save_and_open_page
end

Type guard

# @return [Boolean] response is dumpable (not a redirect)
def dumpable_response?
  response&.response_code && !response.redirection?
end

Try / catch

# Not really rescuable in a useful way; just guard:
save_and_open_page unless response.redirection?

Prevention

When it happens

Trigger: In a request/integration test, calling save_and_open_page (or save_page) right after an action that issued redirect_to — e.g. a successful create action that redirects to show. The test asserts follow_redirect! was not called, so the response is still the 302.

Common situations: Debugging a controller test where you expected a render but got a redirect; calling save_and_open_page inside a block before follow_redirect!; integration test that hits a before_action redirecting for auth.

Related errors


AI-assisted analysis of rails/rails@2c224ba8f2 (2026-08-10). Data as JSON: /api/errors/df2b8f6de091b861. Report an issue: GitHub.