SeleniumHQ/selenium · error · Error::SerializationError
#{name} expected an object on the wire, got #{json_payload.i
Error message
#{name} expected an object on the wire, got #{json_payload.inspect} What it means
A BiDi Union type with every arm being an object (object_only) cannot match a bare scalar payload. from_json returns bare scalars unchanged for normal unions, but for object_only unions a non-Hash payload raises Error::SerializationError because no variant could match.
Source
Thrown at rb/lib/selenium/webdriver/bidi/serialization/union.rb:63
def fallback(path) = @fallback = path
# Declared (via the schema's `objectOnly` signal) on a union whose every arm is an
# object, so a non-Hash payload is a schema violation rather than a scalar arm.
def object_only = @object_only = true
# Declared (via the schema's `scalarValues` signal) on a non-object_only union whose
# bare-scalar arms are a fixed set of literals (input.Origin's "viewport" / "pointer").
# An outbound scalar outside that set matches no arm, so it is a caller error.
def scalar_values(*values) = @scalar_values = values
# A non-Hash payload is a bare scalar arm (e.g. input.Origin's "viewport") with no
# object to dispatch on, so it is returned unchanged — unless every arm is an object
# (object_only), where a non-Hash cannot match any variant and is a wire error.
def from_json(json_payload)
unless json_payload.is_a?(::Hash)
return json_payload unless @object_only
raise Error::SerializationError, "#{name} expected an object on the wire, got #{json_payload.inspect}"
end
variant = select(json_payload)
unless variant
raise Error::SerializationError,
"#{name} received a variant not in this Selenium's BiDi schema: #{json_payload.inspect}"
end
Protocol.const_get(variant).from_json(json_payload)
end
# Outbound mirror of from_json: build the variant the command's kwargs describe
# so its typed as_json drives null-vs-absent per field (a flat hash through
# Transport cannot). Dispatch keys are wire names equal to their ruby kwarg
# (asserted at generation), so they match the kwargs by symbol. A mismatch here
# is a caller error (unlike an unknown inbound value), so it fails loudly.
def build(**kwargs)
variant = outbound_variant(kwargs) ||
raise(::ArgumentError, "no #{name} variant matches #{kwargs.inspect}")View on GitHub (pinned to aa36b38e69)
Solutions
- Inspect the raw payload to confirm a non-object arrived at an object-only union.
- Verify the union is object_only in the current Selenium schema and the browser agrees.
- Align Selenium and browser/driver versions.
- Report the divergence with the payload.
Defensive patterns
Strategy: validation
Validate before calling
def bidi_object?(payload) payload.is_a?(::Hash) end
Type guard
def object_only_union_ok?(payload) payload.is_a?(::Hash) end
Try / catch
begin
value = SomeUnion.from_json(payload)
rescue Selenium::WebDriver::Error::SerializationError => e
raise unless e.message =~ /expected an object on the wire/
warn "object-only union got scalar: #{e.message}"
end Prevention
- Confirm the union is object_only in the current schema before expecting scalar handling.
- Log raw payloads to detect when a bare scalar arrives at an object-only union.
- Pin compatible Selenium/browser versions to avoid schema drift.
When it happens
Trigger: Inbound BiDi payload at an object_only union field that is a non-Hash value (string, number, array, null-ish) — no object arm exists to dispatch to.
Common situations: Browser sends a bare scalar where the schema says every variant is an object, schema/client skew, non-conformant BiDi response.
Related errors
- #{name} received a variant not in this Selenium's BiDi schem
- #{name} expected an object on the wire, got #{json_payload.i
- #{name}##{field.name} is required but was missing from the r
- #{name}##{field.name} received null but is not nullable
- #{name}##{field.name} expected #{field.list ? 'a list' : 'a
AI-assisted analysis of SeleniumHQ/selenium@aa36b38e69 (2026-08-14).
Data as JSON: /api/errors/24e31dcb8b47488e.
Report an issue: GitHub.