{"record":{"id":"98c009c62f68b5d2","repo":"instructure/canvas-lms","slug":"input-value-inspect-is-not-a-valid-stringmap","errorCode":null,"errorMessage":"#{input_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":33,"sourceCode":"# details.\n#\n# You should have received a copy of the GNU Affero General Public License along\n# with this program. If not, see <http://www.gnu.org/licenses/>.\n#\n\nmodule Types\n  class StringMapType < Types::BaseScalar\n    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":15,"sourceCodeEnd":48,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/types/string_map_type.rb#L15-L48","documentation":"StringMapType is a scalar whose coerce_input validates that the value is a Hash of String keys to String values (ActionController::Parameters are first converted to a plain Hash). Anything else — nested hashes, non-string values, arrays, nil — raises GraphQL::CoercionError with this message naming the offending value.","triggerScenarios":"Passing a variable with non-string values (numbers, booleans, nulls) or nested objects into a StringMap-typed argument; sending an array instead of an object; sending a multipart/GraphQL-upload parameter that remains an unconvertible type.","commonSituations":"JS clients stringify JSON in variables but forget to coerce numeric fields (e.g. {\"count\": 5}); building the map from parsed form data that kept integer values; locale-specific metadata fields where one value is null.","solutions":["Stringify every key and value before sending: Object.entries(obj) mapped to String(v).","Reject or coerce null/undefined/numeric/boolean values client-side; omit keys whose values are null.","If you need structured (non-string) data, use a different argument type — StringMap is flat strings only.","Flatten nested objects to string values (e.g. JSON.stringify the sub-object as the value)."],"exampleFix":"// before\nvariables: { metadata: { attempts: 3, notes: null } }\n// after\nvariables: { metadata: { attempts: \"3\", notes: \"\" } } // or omit null keys","handlingStrategy":"validation","validationCode":"function isStringMap(v) {\n  if (v == null || typeof v !== 'object' || Array.isArray(v)) return false;\n  return Object.entries(v).every(([k, val]) => typeof k === 'string' && typeof val === 'string');\n}\nif (!isStringMap(vars.metadata)) throw new Error('metadata must be a flat String->String map');","typeGuard":"const isStringMap = (v) => v !== null && typeof v === 'object' && !Array.isArray(v) && Object.values(v).every(x => typeof x === 'string') && Object.keys(v).every(k => typeof k === 'string');","tryCatchPattern":"try { await gql(MUTATION, vars); } catch (e) { if (e.message.includes('is not a valid StringMap')) { vars = stringifyMapShallow(vars.metadata); return retry(vars); } throw e; }","preventionTips":["Coerce all values with String(v) and drop null/undefined entries before sending.","Never nest objects in a StringMap — JSON.stringify sub-objects as string values if needed.","Add a schema-aware variables validator (e.g. GraphQL Code Generator / validation against the introspected scalar) in your client."],"tags":["graphql","scalar","validation","type-mismatch"],"backgroundTag":"invalid-argument-value","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"}