{"record":{"id":"c55cb92238fed601","repo":"SeleniumHQ/selenium","slug":"argument-should-be-a-hash-or-implement-capabiliti","errorCode":null,"errorMessage":"argument should be a Hash or implement #capabilities","messagePattern":"argument should be a Hash or implement #capabilities","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"rb/lib/selenium/webdriver/remote/capabilities.rb","lineNumber":151,"sourceCode":"        #\n        # Allows setting arbitrary capabilities.\n        #\n\n        def []=(key, value)\n          @capabilities[key] = value\n        end\n\n        def [](key)\n          @capabilities[key]\n        end\n\n        def merge!(other)\n          if other.respond_to?(:capabilities, true) && other.capabilities.is_a?(Hash)\n            @capabilities.merge! other.capabilities\n          elsif other.is_a? Hash\n            @capabilities.merge! other\n          else\n            raise ArgumentError, 'argument should be a Hash or implement #capabilities'\n          end\n        end\n\n        def proxy\n          @capabilities[:proxy]\n        end\n\n        def proxy=(proxy)\n          case proxy\n          when Hash\n            @capabilities[:proxy] = Proxy.new(proxy)\n          when Proxy, nil\n            @capabilities[:proxy] = proxy\n          else\n            raise TypeError, \"expected Hash or #{Proxy.name}, got #{proxy.inspect}:#{proxy.class}\"\n          end\n        end\n","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/SeleniumHQ/selenium/blob/aa36b38e696a0909e973bdf5e2f9031ffe842c4b/rb/lib/selenium/webdriver/remote/capabilities.rb#L133-L169","documentation":"Raised by Remote::Capabilities#merge! when the argument is neither a Hash nor an object that responds to #capabilities with a Hash result. The method uses respond_to?(:capabilities, true) to detect capabilities-bearing objects and falls back to is_a?(Hash); anything else is rejected to prevent silent corruption of the internal @capabilities hash.","triggerScenarios":"Calling capabilities.merge!(some_string), capabilities.merge!(an_array), or capabilities.merge!(a_driver_instance). Passing a struct or Data object that holds capability data but does not expose a #capabilities method. Passing nil or an OpenStruct that lacks #capabilities.","commonSituations":"Attempting to merge a single key-value pair as a two-element array instead of a Hash. Passing a WebDriver::Options instance expecting it to work (Options does not expose #capabilities — it exposes #as_json). Confusing merge! with the constructor which accepts different shapes. Refactoring that changed what object flows into merge!.","solutions":["Ensure the argument is a plain Hash: capabilities.merge!({browserName: 'chrome'}).","If merging another Capabilities object, confirm it responds to #capabilities and that method returns a Hash — or call .capabilities on it explicitly first.","If you have an Options object, call .as_json or extract its hash form before merging.","Wrap the argument in a Hash constructor: capabilities.merge!(Hash(other)) only if the object is safely coercible."],"exampleFix":"# before\ncaps.merge!(driver.options)\n\n# after\ncaps.merge!(driver.options.as_json)","handlingStrategy":"validation","validationCode":"# Validate before merge!:\nunless other.is_a?(Hash) || (other.respond_to?(:capabilities, true) && other.capabilities.is_a?(Hash))\n  raise ArgumentError, 'merge! requires a Hash or object with #capabilities returning a Hash'\nend\ncapabilities.merge!(other)","typeGuard":"# Check the argument is mergeable before calling:\ndef mergeable?(obj)\n  obj.is_a?(Hash) || (obj.respond_to?(:capabilities, true) && obj.capabilities.is_a?(Hash))\nend","tryCatchPattern":"begin\n  capabilities.merge!(other)\nrescue ArgumentError => e\n  # coerce if possible, else report\n  capabilities.merge!(other.to_h) if other.respond_to?(:to_h)\nend","preventionTips":["Always pass a Hash literal or another Capabilities object to merge!.","If accepting external input, coerce to Hash first: Hash(obj) or obj.to_h.","Do not pass Options objects to merge! — use .as_json or extract capabilities first."],"tags":["argument-error","capabilities","merge","type-mismatch"],"backgroundTag":null,"analyzedSha":"aa36b38e696a0909e973bdf5e2f9031ffe842c4b","analyzedAt":"2026-08-14T02:32:32.244Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}