{"record":{"id":"1c844bb9dd5b365b","repo":"instructure/canvas-lms","slug":"invalid-ratings-value-rating","errorCode":null,"errorMessage":"invalid ratings value: #{rating}","messagePattern":"invalid ratings value: #(.+?)","errorType":"validation","errorClass":null,"httpStatus":500,"severity":"error","filePath":"app/controllers/outcomes_academic_benchmark_import_api_controller.rb","lineNumber":137,"sourceCode":"    unless LearningOutcome.valid_calculation_method?(value)\n      raise \"invalid calculation_method: #{value}\"\n    end\n\n    value\n  end\n\n  def parse_calculation_int(calc_method, value)\n    int = value.nil? ? nil : parse_int(value)\n    unless LearningOutcome.valid_calculation_int?(int, calc_method)\n      raise \"invalid calculation_int: #{value}\"\n    end\n\n    int\n  end\n\n  def parse_rating(rating)\n    if rating.nil? || !rating.is_a?(ActionController::Parameters)\n      raise \"invalid ratings value: #{rating}\"\n    end\n    if rating[:description].nil? || !rating[:description].is_a?(String)\n      raise \"invalid description value: #{rating[:description]}\"\n    end\n\n    { description: rating[:description], points: parse_int(rating[:points]) }\n  end\nend\n","sourceCodeStart":119,"sourceCodeEnd":146,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/controllers/outcomes_academic_benchmark_import_api_controller.rb#L119-L146","documentation":"OutcomesAcademicBenchmarkImportApiController#parse_rating requires each rating entry to be a non-nil ActionController::Parameters object and raises otherwise. This ensures each mastery rating in the ratings array is a structured parameter object with description and points.","triggerScenarios":"Passing a rating entry that is a plain hash, string, number, or nil inside the :ratings array — e.g. ratings: ['Mastery'] or ratings: [nil].","commonSituations":"Sending plain JSON objects that arrive as Hash/HashWithIndifferentAccess rather than ActionController::Parameters depending on the call path; array of strings from a simplified form; nil entries from sparse data.","solutions":["Send each rating as an object with description (string) and points (integer).","If calling the controller helper directly from Ruby, wrap hashes in ActionController::Parameters.","Filter out nil entries from the ratings array before submission.","Validate each entry client-side before calling the API."],"exampleFix":"// before\nratings: [\"Mastery\", \"Near\"]\n// after\nratings: [{ description: \"Mastery\", points: 3 }, { description: \"Near\", points: 2 }]","handlingStrategy":"type-guard","validationCode":"raise ArgumentError unless ratings.all? { |r| r.is_a?(ActionController::Parameters) }","typeGuard":"def rating_param?(r) = !r.nil? && r.is_a?(ActionController::Parameters)","tryCatchPattern":"begin\n  import_outcomes(options)\nrescue RuntimeError => e\n  raise InvalidRatingEntry, e.message if e.message.start_with?('invalid ratings value:')\n  raise\nend","preventionTips":["Send each rating as an object, never a string or nil.","Wrap raw hashes in ActionController::Parameters when calling helpers directly.","Compact the ratings array to drop nils.","Validate entry shape client-side."],"tags":["api","ratings","validation"],"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"}