{"record":{"id":"8aa3f220aa452993","repo":"SeleniumHQ/selenium","slug":"expected-string-or-symbol-got-key-inspect-ke","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/common/options.rb","lineNumber":215,"sourceCode":"        end\n      end\n\n      def process_json_hash(value, camelize_keys)\n        value.each_with_object({}) do |(key, val), hash|\n          next if val.respond_to?(:empty?) && val.empty?\n\n          camelize = camelize_keys ? camelize?(key) : false\n          key = convert_json_key(key, camelize: camelize)\n          hash[key] = generate_as_json(val, camelize_keys: camelize)\n        end\n      end\n\n      def convert_json_key(key, camelize: true)\n        key = key.to_s if key.is_a?(Symbol)\n        key = camel_case(key) if camelize\n        return key if key.is_a?(String)\n\n        raise TypeError, \"expected String or Symbol, got #{key.inspect}:#{key.class}\"\n      end\n\n      def camel_case(str)\n        str.gsub(/_([a-z])/) { Regexp.last_match(1)&.upcase }\n      end\n    end # Options\n  end # WebDriver\nend # Selenium\n","sourceCodeStart":197,"sourceCodeEnd":224,"githubUrl":"https://github.com/SeleniumHQ/selenium/blob/aa36b38e696a0909e973bdf5e2f9031ffe842c4b/rb/lib/selenium/webdriver/common/options.rb#L197-L224","documentation":"convert_json_key normalizes hash keys during JSON serialization and accepts only String or Symbol keys. After converting a Symbol to a String (and optionally camelCasing it), any remaining non-String key raises TypeError. This typically originates from an Integer or arbitrary object used as an options key via add_option or direct hash mutation.","triggerScenarios":"Calling options.add_option(123, value) with an Integer key. Storing an object (non-String/Symbol) as a key in the options hash. Using a Class or Numeric as an option key.","commonSituations":"Programmatically generating option keys from numeric IDs. Accidentally storing a configuration object as a hash key. Migrating data structures that use Integer keys.","solutions":["Use only String or Symbol keys when calling add_option or mutating options.options.","Convert numeric/object keys to Symbols or Strings before adding them.","Validate that every key in a dynamically-built options hash is_a?(String) || is_a?(Symbol)."],"exampleFix":"# before\noptions.add_option(123, true)\n\n# after\noptions.add_option(:'option_123', true)","handlingStrategy":"type-guard","validationCode":"raise TypeError, 'option key must be String or Symbol' unless key.is_a?(String) || key.is_a?(Symbol)","typeGuard":"def valid_option_key?(key)\n  key.is_a?(String) || key.is_a?(Symbol)\nend","tryCatchPattern":"begin\n  options.add_option(key, value)\nrescue TypeError => e\n  raise unless e.message.include?('expected String or Symbol')\n  options.add_option(key.to_s, value)\nend","preventionTips":["Always pass String or Symbol keys to add_option.","Sanitize dynamically-generated keys with .to_s or .to_sym.","Avoid storing arbitrary objects as hash keys in options.options."],"tags":["ruby","options","json","type-error","serialization"],"backgroundTag":null,"analyzedSha":"aa36b38e696a0909e973bdf5e2f9031ffe842c4b","analyzedAt":"2026-08-14T02:32:32.244Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}