{"record":{"id":"ce11bce5cc49ba40","repo":"instructure/canvas-lms","slug":"ruby-value-inspect-is-not-a-valid-stringmap","errorCode":null,"errorMessage":"#{ruby_value.inspect} is not a valid StringMap","messagePattern":"#(.+?) is not a valid StringMap","errorType":"validation","errorClass":"GraphQL::CoercionError","httpStatus":null,"severity":"error","filePath":"app/graphql/types/string_map_type.rb","lineNumber":41,"sourceCode":"    description \"A hash with string keys and string values\"\n\n    def self.coerce_input(input_value, _context)\n      return nil if input_value.nil?\n\n      if input_value.is_a?(ActionController::Parameters)\n        input_value = input_value.to_unsafe_h\n      end\n\n      unless input_value.is_a?(Hash) && input_value.all? { |k, v| k.is_a?(String) && v.is_a?(String) }\n        raise GraphQL::CoercionError, \"#{input_value.inspect} is not a valid StringMap\"\n      end\n\n      input_value\n    end\n\n    def self.coerce_result(ruby_value, _context)\n      unless ruby_value.is_a?(Hash) && ruby_value.all? { |k, v| (k.is_a?(Symbol) || k.is_a?(String)) && v.is_a?(String) }\n        raise GraphQL::CoercionError, \"#{ruby_value.inspect} is not a valid StringMap\"\n      end\n\n      ruby_value.transform_keys(&:to_s)\n    end\n  end\nend\n","sourceCodeStart":23,"sourceCodeEnd":48,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/types/string_map_type.rb#L23-L48","documentation":"StringMapType is a custom GraphQL scalar mapping String keys to String values. coerce_result runs on every value the server returns through this scalar; if the value is not a Hash whose keys are all Symbols/Strings and values are all Strings, a GraphQL::CoercionError is raised so the client receives a well-formed GraphQL error instead of silently serializing bad data. Valid values are normalized with transform_keys(&:to_s).","triggerScenarios":"A resolver/field returning a StringMap scalar yields a non-Hash (nil, array, model object), a Hash with non-string/symbol keys (e.g. integer keys), or a Hash whose values are not Strings (integers, booleans, nested hashes, nil).","commonSituations":"Returning parsed JSON where some values are numbers; returning ActiveRecord attributes with integer values; forgetting to to_s values before returning; passing nil when a lookup misses.","solutions":["Inspect the value in the message — it prints the offending ruby_value.inspect — and make the resolver return a Hash of String/Symbol keys to String values","Coerce before returning: value.transform_values(&:to_s) when values are non-string primitives","Filter out nil or non-hash lookups: return {} instead of nil","Add a spec covering the resolver's return shape through GraphQL execution"],"exampleFix":"// before\n{ counts: { apples: 3, bananas: 1 } }\n// after\n{ counts: { apples: '3', bananas: '1' } }","handlingStrategy":"type-guard","validationCode":"def valid_string_map?(v)\n  v.is_a?(Hash) && v.all? { |k, val| (k.is_a?(Symbol) || k.is_a?(String)) && val.is_a?(String) }\nend","typeGuard":"def valid_string_map?(v)\n  v.is_a?(Hash) && v.all? { |k, val| (k.is_a?(Symbol) || k.is_a?(String)) && val.is_a?(String) }\nend","tryCatchPattern":"begin\n  result = resolver_value\nrescue GraphQL::CoercionError => e\n  Rails.logger.error(\"StringMap coercion failed: #{e.message}\")\n  {}\nend","preventionTips":["transform_values(&:to_s) on any hash returned through a StringMap field","Never return nil from a StringMap resolver; return {}","Add a unit test asserting the resolver's return shape"],"tags":["graphql","scalar-coercion","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}