SeleniumHQ/selenium · error · TypeError

#{action.inspect} is not a valid action

Error message

#{action.inspect} is not a valid action

What it means

Raised as TypeError by InputDevice#add_action when the supplied object's class is not a descendant of Interaction (action.class < Interaction returns false/nil). InputDevice is @api private and underpins PointerInput / KeyInput / WheelInput / NoneInput; the guard ensures only well-formed Interaction subclasses enter the action list that gets encoded to the W3C actions payload.

Source

Thrown at rb/lib/selenium/webdriver/common/interactions/input_device.rb:41

  module WebDriver
    module Interactions
      #
      # Superclass for the input device sources
      # Manages Array of Interaction instances for the device
      #
      # @api private
      #

      class InputDevice
        attr_reader :name, :actions, :type

        def initialize(name = nil)
          @name = name || SecureRandom.uuid
          @actions = []
        end

        def add_action(action)
          raise TypeError, "#{action.inspect} is not a valid action" unless action.class < Interaction

          @actions << action
        end

        def clear_actions
          @actions.clear
        end

        def create_pause(duration = 0)
          add_action(Pause.new(self, duration))
        end

        def encode
          {type: type, id: name, actions: @actions.map(&:encode)} unless @actions.empty?
        end
      end # InputDevice
    end # Interactions
  end # WebDriver

View on GitHub (pinned to aa36b38e69)

Solutions

  1. Use the public action DSL (driver.action.move_to(...).click.perform) instead of touching InputDevice#add_action directly.
  2. If you must extend, ensure the object subclasses Selenium::WebDriver::Interactions::Interaction and is constructed with a valid source before being added.

Example fix

# before
pointer.add_action({type: 'pointerDown', button: 0}) # => TypeError: {:type=>...} is not a valid action

# after
pointer.add_action(Selenium::WebDriver::Interactions::PointerPress.new(pointer, :down, :left))
Defensive patterns

Strategy: type-guard

Type guard

# Ensure only Interaction subclasses reach add_action
def interaction?(obj)
  obj.is_a?(Selenium::WebDriver::Interactions::Interaction)
end

pointer.add_action(obj) if interaction?(obj)

Prevention

When it happens

Trigger: Calling input_device.add_action(obj) where obj is anything other than an instance of an Interaction subclass (Pause, PointerMove, PointerPress, PointerCancel, TypingInteraction, Scroll). E.g. passing a Hash, a Symbol, or a plain object.

Common situations: Only hit by code that hand-builds action devices instead of using the public ActionBuilder / driver.action DSL. Typically a custom ActionBuilder extension or a copy-paste that passes the wrong object to add_action.

Related errors


AI-assisted analysis of SeleniumHQ/selenium@aa36b38e69 (2026-08-14). Data as JSON: /api/errors/d29de4a72ce13332. Report an issue: GitHub.