teamcapybara/capybara · error · ArgumentError

You may only upload files: #{local_file.inspect}

Error message

You may only upload files: #{local_file.inspect}

What it means

Raised by the Selenium Firefox node when #attach_file (setting a file input) is given a path that is not an existing regular file (File.file? returns false). Firefox/geckodriver cannot set files directly on the input the way Chrome can, so Capybara zips the local file and POSTs it to geckodriver's session/:session_id/file endpoint, which requires a real on-disk file. The message echoes the inspected path that failed the check.

Source

Thrown at lib/capybara/selenium/nodes/firefox_node.rb:127

    when String
      # https://bugzilla.mozilla.org/show_bug.cgi?id=1405370
      keys = keys.upcase if (browser_version < 64.0) && down_keys&.include?(:shift)
      actions.send_keys(keys)
    when Symbol
      actions.send_keys(keys)
    when Array
      down_keys.push
      keys.each { |sub_keys| _send_keys(sub_keys, actions, down_keys) }
      down_keys.pop.reverse_each { |key| actions.key_up(key) }
    else
      raise ArgumentError, 'Unknown keys type'
    end
    actions
  end

  def upload(local_file)
    return nil unless local_file
    raise ArgumentError, "You may only upload files: #{local_file.inspect}" unless File.file?(local_file)

    file = ::Selenium::WebDriver::Zipper.zip_file(local_file)
    bridge.http.call(:post, "session/#{bridge.session_id}/file", file: file)['value']
  end

  def browser_version
    driver.browser.capabilities[:browser_version].to_f
  end
end

View on GitHub (pinned to 15b5fdb76e)

Solutions

  1. Verify the path before attaching: raise "fixture missing: #{path}" unless File.file?(path)
  2. Build absolute paths from a known root: Rails.root.join('spec/fixtures/files/doc.pdf') or File.expand_path('...', __dir__)
  3. If the file is generated at runtime, make sure the write completes (file closed/flushed) before attach_file
  4. Print Dir.pwd in the failing spec to catch working-directory drift between local and CI runners

Example fix

# before
page.attach_file('Resume', 'spec/fixtures/files/resume.pdf')

# after
path = File.expand_path('spec/fixtures/files/resume.pdf', __dir__)
raise "fixture missing: #{path}" unless File.file?(path)
page.attach_file('Resume', path)
Defensive patterns

Strategy: validation

Validate before calling

def uploadable?(path)
  path.is_a?(String) && File.file?(path)
end

page.attach_file('Resume', path) if uploadable?(path)

Type guard

def assert_uploadable_file!(path)
  return path if path.is_a?(String) && File.file?(path)
  raise ArgumentError, "not an existing file: #{path.inspect}"
end

page.attach_file('Resume', assert_uploadable_file!(path))

Try / catch

begin
  page.attach_file('Resume', path)
rescue ArgumentError => e
  raise "fixture problem (pwd=#{Dir.pwd}): #{e.message}"
end

Prevention

When it happens

Trigger: Calling page.attach_file('Resume', 'spec/fixtures/files/missing.pdf') (or any #set on a file field) under the Selenium Firefox driver where the path does not exist, points to a directory, or is relative and does not resolve from the process working directory (Dir.pwd differs between rspec, rake, spring, and IDE runners).

Common situations: Specs run from a different working directory breaking relative fixture paths; typo'd fixture filenames; attaching before a generated file is written/closed; passing a directory instead of a file; CI checkout layout differing from local.

Related errors


AI-assisted analysis of teamcapybara/capybara@15b5fdb76e (2026-08-21). Data as JSON: /api/errors/e99adfbd0763a54d. Report an issue: GitHub.