vcr/vcr · error · ArgumentError

`VCR.use_cassette` requires a block. If you cannot wrap your

Error message

`VCR.use_cassette` requires a block. If you cannot wrap your code in a block, use `VCR.insert_cassette` / `VCR.eject_cassette` instead.

What it means

VCR.use_cassette is a block-scoped API: it inserts a cassette, runs the block, and ejects in an ensure clause. Called without a block it raises ArgumentError pointing you to VCR.insert_cassette / VCR.eject_cassette for non-block use cases (lib/vcr.rb:186).

Source

Thrown at lib/vcr.rb:186

  # block, and ejects the cassette.
  #
  # @example
  #   VCR.use_cassette('twitter', record: :new_episodes) do
  #     # make an HTTP request
  #   end
  #
  # @param (see #insert_cassette)
  # @option (see #insert_cassette)
  # @yield Block to run while this cassette is in use.
  # @yieldparam cassette [(optional) VCR::Cassette] the cassette that has
  #  been inserted.
  # @raise (see #insert_cassette)
  # @return [void]
  # @see #insert_cassette
  # @see #eject_cassette
  def use_cassette(name, options = {}, &block)
    unless block
      raise ArgumentError, "`VCR.use_cassette` requires a block. " +
                           "If you cannot wrap your code in a block, use " +
                           "`VCR.insert_cassette` / `VCR.eject_cassette` instead."
    end

    cassette = insert_cassette(name, options)

    begin
      call_block(block, cassette)
    rescue StandardError
      cassette.run_failed!
      raise
    ensure
      eject_cassette
    end
  end

  # Inserts multiple cassettes the given names
  #

View on GitHub (pinned to a747bb6478)

Solutions

  1. Add the block: VCR.use_cassette('api') do ... end
  2. If the code cannot be wrapped in a block (e.g. cassette must span helper methods or setup/teardown), switch to the explicit API: cassette = VCR.insert_cassette('api') ... VCR.eject_cassette
  3. If a helper wraps use_cassette, forward the caller's block with &block

Example fix

# before
VCR.use_cassette('api')
client.get('/repos') # ArgumentError, and never recorded

# after
VCR.use_cassette('api') do
  client.get('/repos')
end

# non-block alternative
cassette = VCR.insert_cassette('api')
client.get('/repos')
VCR.eject_cassette
Defensive patterns

Strategy: validation

Validate before calling

def with_cassette(name, options = {}, &block)
  raise ArgumentError, 'a block is required' unless block
  VCR.use_cassette(name, options, &block)
end

Prevention

When it happens

Trigger: VCR.use_cassette('api') with no do...end (forgotten or removed in a refactor); expecting the cassette to stay active for the rest of the file; passing a lambda in the options hash instead of as the actual block, e.g. VCR.use_cassette('api', &nil) or VCR.use_cassette('api', block_as_option: proc { }); multiline calls where the do keyword was accidentally deleted.

Common situations: Refactors that extracted the body into a helper without forwarding the block (&block); developers wanting a file-wide cassette; copy-paste from examples that used insert/eject style; rspec metadata-based cassette usage mixed with manual calls.

Related errors


AI-assisted analysis of vcr/vcr@a747bb6478 (2026-08-21). Data as JSON: /api/errors/770adab9e0c2ed17. Report an issue: GitHub.