{"record":{"id":"566d9426d122d86c","repo":"SeleniumHQ/selenium","slug":"expected-string-or-symbol-got-key-inspect-ke-566d94","errorCode":null,"errorMessage":"expected String or Symbol, got #{key.inspect}:#{key.class}","messagePattern":"expected String or Symbol, got #(.+?):#(.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"rb/lib/selenium/webdriver/remote/capabilities.rb","lineNumber":252,"sourceCode":"          when Hash\n            value.each_with_object({}) do |(k, v), h|\n              h[convert_key(k)] = process_capabilities(k, v, h)\n            end\n          when Capabilities, Options\n            value.as_json\n          else\n            convert_value(key, value)\n          end\n        end\n\n        def convert_key(key)\n          case key\n          when String\n            key.to_s\n          when Symbol\n            self.class.camel_case(key)\n          else\n            raise TypeError, \"expected String or Symbol, got #{key.inspect}:#{key.class}\"\n          end\n        end\n\n        def convert_value(key, value)\n          case key\n          when :platform\n            value.to_s.upcase\n          when :proxy\n            value&.as_json\n          when :unhandled_prompt_behavior\n            value.is_a?(Symbol) ? value.to_s.tr('_', ' ') : value\n          else\n            value\n          end\n        end\n      end # Capabilities\n    end # Remote\n  end # WebDriver","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/SeleniumHQ/selenium/blob/aa36b38e696a0909e973bdf5e2f9031ffe842c4b/rb/lib/selenium/webdriver/remote/capabilities.rb#L234-L270","documentation":"Raised as a TypeError by Capabilities#convert_key when a capability key is neither a String nor a Symbol. convert_key normalizes keys to camelCase strings for the W3C/JSON wire protocol; String keys pass through as-is, Symbol keys are camel-cased, and any other type (Integer, Array, nil used as key) is rejected because it cannot form a valid capability name.","triggerScenarios":"Using an Integer as a key: caps[0] = 'value' followed by serialization. Passing a hash with non-string/symbol keys via the Capabilities constructor. Iterating over external data (e.g. parsed JSON with integer keys from a numeric-indexed structure) and assigning each to capabilities. Using a Class or Module object as a key.","commonSituations":"Loading capability overrides from YAML/JSON where keys are deserialized as non-strings in edge cases. Programmatic hash building that accidentally uses an integer index. Passing a Data/Struct field name object instead of a symbol. Refactoring from indifferent-access hashes that exposed integer lookups.","solutions":["Ensure all capability keys are Symbols (preferred) or Strings: caps[:browserName] = 'chrome'.","When loading from external data, coerce keys: external.each { |k, v| caps[k.to_sym] = v }.","Filter out non-string/symbol keys before assignment if the source data is untrusted or mixed."],"exampleFix":"# before\nconfig.each { |k, v| caps[k] = v }  # k may be Integer\n\n# after\nconfig.each { |k, v| caps[k.to_sym] = v if k.respond_to?(:to_sym) }","handlingStrategy":"validation","validationCode":"# Coerce keys to Symbol before assignment:\nsafe_keys = external_hash.select { |k, _| k.is_a?(String) || k.is_a?(Symbol) }\nsafe_keys.each { |k, v| capabilities[k.to_sym] = v }","typeGuard":"def valid_capability_key?(key)\n  key.is_a?(String) || key.is_a?(Symbol)\nend","tryCatchPattern":"begin\n  capabilities[key] = value\nrescue TypeError\n  capabilities[key.to_sym] = value if key.respond_to?(:to_sym)\nend","preventionTips":["Use Symbol keys consistently for all capabilities.","When loading from external data (YAML, JSON), coerce keys with .to_sym.","Filter out non-string/symbol keys from untrusted sources before assignment."],"tags":["type-error","capabilities","key-validation","serialization"],"backgroundTag":null,"analyzedSha":"aa36b38e696a0909e973bdf5e2f9031ffe842c4b","analyzedAt":"2026-08-14T02:32:32.244Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}