SeleniumHQ/selenium · error · Error::SerializationError

#{name}##{field.name} expected #{field.primitive}, got #{raw

Error message

#{name}##{field.name} expected #{field.primitive}, got #{raw.inspect}

What it means

check_primitive validates that a BiDi field's value matches its declared primitive (string/boolean/number/integer). number accepts any Numeric; integer requires an Integer (rejecting e.g. 1.5). A value whose Ruby type does not match raises Error::SerializationError. Fields with no primitive descriptor are unchecked.

Source

Thrown at rb/lib/selenium/webdriver/bidi/serialization/record.rb:288

              raise Error::SerializationError,
                    "#{name}##{field.name} expected #{field.list ? 'a list' : 'a single value'}, got #{raw.inspect}"
            end

            # Ruby classes a checkable primitive admits. `number` is any Numeric (JSON has one
            # number type); `integer` requires an Integer — a browser emits `5`, not `5.0`, for an
            # integer (JS has no int/float split), so this rarely false-positives yet still rejects
            # a genuine non-integer like 1.5. A field with no primitive descriptor is left unchecked.
            PRIMITIVE_TYPES = {
              'string' => [::String], 'boolean' => [::TrueClass, ::FalseClass],
              'number' => [::Numeric], 'integer' => [::Integer]
            }.freeze

            def check_primitive(field, raw)
              expected = PRIMITIVE_TYPES[field.primitive]
              return if expected.nil? || expected.any? { |type| raw.is_a?(type) }

              raise Error::SerializationError, "#{name}##{field.name} expected #{field.primitive}, got #{raw.inspect}"
            end

            def enum_hash(field)
              (@enums ||= {})[field.name] ||= Protocol.const_get(field.enum)
            end

            # Parses each element. A `scalar` field is a map encoded as `[key, value]` pairs, so
            # every element must be a 2-item pair — each is read as one, and a malformed entry is
            # rejected. Non-scalar lists recurse into nested lists; other elements deserialize.
            def read_list(field, raw, klass)
              raw.map do |element|
                if field.scalar
                  read_map_entry(field, element, klass)
                elsif element.is_a?(::Array)
                  read_list(field, element, klass)
                else
                  klass.from_json(element)
                end

View on GitHub (pinned to aa36b38e69)

Solutions

  1. Inspect the raw value to see the actual type that arrived.
  2. Confirm the field's primitive in the W3C BiDi spec.
  3. Align Selenium and browser/driver versions.
  4. Report the non-conformant payload upstream.
Defensive patterns

Strategy: validation

Validate before calling

PRIM = { 'string' => String, 'boolean' => [TrueClass, FalseClass], 'integer' => Integer, 'number' => Numeric }.freeze

def expect_primitive!(value, prim, field)
  types = Array(PRIM[prim])
  raise "#{field} expected #{prim}, got #{value.class}" unless types.any? { |t| value.is_a?(t) }
  value
end

Type guard

def primitive_match?(value, prim)
  Array({ 'string' => String, 'boolean' => [TrueClass, FalseClass], 'integer' => Integer, 'number' => Numeric }[prim]).any? { |t| value.is_a?(t) }
end

Try / catch

begin
  record = SomeRecord.from_json(payload)
rescue Selenium::WebDriver::Error::SerializationError => e
  raise unless e.message =~ /expected (string|boolean|number|integer)/
  warn "primitive mismatch: #{e.message}"
end

Prevention

When it happens

Trigger: Inbound BiDi payload carries a value of the wrong primitive type at a typed field — e.g. a string where integer is expected, or 1.5 where integer is expected, or a number where boolean is expected.

Common situations: Browser emits a value in an unexpected form, server bug, schema/client skew, a numeric field receiving a string from a non-conformant grid.

Related errors


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