{"record":{"id":"472ae9afc98b5478","repo":"ankane/searchkick","slug":"all-fields-in-per-field-misspellings-must-also-be","errorCode":null,"errorMessage":"All fields in per-field misspellings must also be specified in fields option","messagePattern":"All fields in per-field misspellings must also be specified in fields option","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/searchkick/query.rb","lineNumber":328,"sourceCode":"          end\n\n          if misspellings != false\n            edit_distance = (misspellings.is_a?(Hash) && (misspellings[:edit_distance] || misspellings[:distance])) || 1\n            transpositions =\n              if misspellings.is_a?(Hash) && misspellings.key?(:transpositions)\n                {fuzzy_transpositions: misspellings[:transpositions]}\n              else\n                {fuzzy_transpositions: true}\n              end\n            prefix_length = (misspellings.is_a?(Hash) && misspellings[:prefix_length]) || 0\n            default_max_expansions = @misspellings_below ? 20 : 3\n            max_expansions = (misspellings.is_a?(Hash) && misspellings[:max_expansions]) || default_max_expansions\n            misspellings_fields = misspellings.is_a?(Hash) && misspellings.key?(:fields) && misspellings[:fields].map(&:to_s)\n\n            if misspellings_fields\n              missing_fields = misspellings_fields - fields.map { |f| base_field(f) }\n              if missing_fields.any?\n                raise ArgumentError, \"All fields in per-field misspellings must also be specified in fields option\"\n              end\n            end\n\n            @misspellings = true\n          else\n            @misspellings = false\n          end\n\n          fields.each do |field|\n            queries_to_add = []\n            qs = []\n\n            factor = boost_fields[field] || 1\n            shared_options = {\n              query: term,\n              boost: 10 * factor\n            }\n","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/ankane/searchkick/blob/93e901a75b11a25101668a616e006b158251b16e/lib/searchkick/query.rb#L310-L346","documentation":"Per-field misspellings (`misspellings: {fields: [...]}`) replace fuzziness on the default field set with fuzziness only on the listed fields, and searchkick's query builder indexes each misspelling field against the query's `fields` list. If a field appears in `misspellings[:fields]` but not in the resolved `fields` (compared after stripping multi-field suffixes via `base_field`), there is no query to attach the fuzzy variant to, so it raises `ArgumentError`.","triggerScenarios":"`Product.search(\"milk\", fields: [:name], misspellings: {fields: [:name, :brand]})` — `:brand` is missing from `fields`. Also caught: suffix mismatches like listing `name.word_start` in misspellings fields while `fields: [:name]` (base_field handles the common cases, but a truly absent field is not).","commonSituations":"Disabling fuzziness for one noisy field and forgetting to add the remaining searchable fields to `fields:`; renaming an attribute in the model but not in the misspellings hash; using `fields: [{name: :exact}]`-style entries while listing plain `:name` or vice versa in misspellings.","solutions":["Add every misspellings field to `fields:`: `fields: [:name, :brand], misspellings: {fields: [:brand]}` (order does not matter, membership does).","If you meant to search all default fields, drop the per-field hash and use `misspellings: false`/default instead.","Ensure the names match the searchable attributes exactly (symbols vs strings are both fine; suffixes like `.analyzed` are normalized by base_field).","Add a unit test that builds the query (`Product.search(...).to_curl` or checking `payload`) to catch this before runtime."],"exampleFix":"# before\nProduct.search(\"milk\", fields: [:name], misspellings: {fields: [:name, :brand]})\n# => ArgumentError: All fields in per-field misspellings must also be specified in fields option\n\n# after\nProduct.search(\"milk\", fields: [:name, :brand], misspellings: {fields: [:brand]})","handlingStrategy":"validation","validationCode":"def fuzzy_search(term, fields:, misspellings_fields: [])\n  missing = Array(misspellings_fields).map(&:to_s) - Array(fields).map { |f| f.to_s.split(\".\").first }\n  raise ArgumentError, \"misspellings fields not in fields: #{missing.join(', ')}\" if missing.any?\n  Product.search(term, fields: fields, misspellings: {fields: misspellings_fields})\nend","typeGuard":"def misspellings_subset_of_fields?(misspellings_fields, fields)\n  base = fields.map { |f| f.to_s.split(\"^\").first.to_s.split(\".\").first }\n  Array(misspellings_fields).map(&:to_s).all? { |f| base.include?(f) }\nend","tryCatchPattern":null,"preventionTips":["Derive the search `fields:` list and the misspellings sub-list from one shared constant.","When disabling fuzziness per field, start from the full field list and subtract, rather than retyping names.","Unit-test query construction for per-field misspellings after model attribute renames."],"tags":["searchkick","misspellings","fuzzy-search","fields","argumenterror"],"backgroundTag":"invalid-option-combination","analyzedSha":"93e901a75b11a25101668a616e006b158251b16e","analyzedAt":"2026-08-21T19:06:23.767Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}