instructure/canvas-lms · error · GraphQL::CoercionError
# is not a valid StringMap
Error message
#{ruby_value.inspect} is not a valid StringMap What it means
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).
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
Example fix
// before
{ counts: { apples: 3, bananas: 1 } }
// after
{ counts: { apples: '3', bananas: '1' } } Defensive patterns
Strategy: type-guard
Validate before calling
def valid_string_map?(v)
v.is_a?(Hash) && v.all? { |k, val| (k.is_a?(Symbol) || k.is_a?(String)) && val.is_a?(String) }
end Type guard
def valid_string_map?(v)
v.is_a?(Hash) && v.all? { |k, val| (k.is_a?(Symbol) || k.is_a?(String)) && val.is_a?(String) }
end Try / catch
begin
result = resolver_value
rescue GraphQL::CoercionError => e
Rails.logger.error("StringMap coercion failed: #{e.message}")
{}
end Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- filter values must be JSON-compatible types
- # is not a valid StringMap
- and cannot be used together
- and cannot be used together
- A course with that id does not exist
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/ce11bce5cc49ba40.
Report an issue: GitHub.
Appendix: source
Thrown at app/graphql/types/string_map_type.rb:41
description "A hash with string keys and string values"
def self.coerce_input(input_value, _context)
return nil if input_value.nil?
if input_value.is_a?(ActionController::Parameters)
input_value = input_value.to_unsafe_h
end
unless input_value.is_a?(Hash) && input_value.all? { |k, v| k.is_a?(String) && v.is_a?(String) }
raise GraphQL::CoercionError, "#{input_value.inspect} is not a valid StringMap"
end
input_value
end
def self.coerce_result(ruby_value, _context)
unless ruby_value.is_a?(Hash) && ruby_value.all? { |k, v| (k.is_a?(Symbol) || k.is_a?(String)) && v.is_a?(String) }
raise GraphQL::CoercionError, "#{ruby_value.inspect} is not a valid StringMap"
end
ruby_value.transform_keys(&:to_s)
end
end
end
View on GitHub (pinned to 1c9f0bb801)