instructure/canvas-lms · error
ratings expected to be an array
Error message
ratings expected to be an array
What it means
OutcomesAcademicBenchmarkImportApiController#valid_options checks that the optional ratings attribute is an Array before parsing each rating and raises otherwise. Ratings (mastery rubric levels) must arrive as an array of parameter objects.
Solutions
- Wrap rating objects in an array: ratings: [{description: ..., points: ...}, ...].
- Send an empty array or omit the :ratings key if there are no ratings.
- Ensure the JSON body is not being flattened before reaching the endpoint.
- Validate Array.isArray/ratings.is_a?(Array) client-side.
Example fix
// before
ratings: { description: "Mastery", points: 3 }
// after
ratings: [{ description: "Mastery", points: 3 }] Defensive patterns
Strategy: type-guard
Validate before calling
raise ArgumentError, "ratings must be an Array" unless ratings.is_a?(Array)
Type guard
def ratings_array?(opts) = opts[:ratings].nil? || opts[:ratings].is_a?(Array)
Try / catch
begin import_outcomes(options) rescue RuntimeError => e raise InvalidRatingsPayload, e.message if e.message == 'ratings expected to be an array' raise end
Prevention
- Always serialize ratings as a JSON array.
- Don't unwrap single-element rating collections.
- Omit :ratings entirely when there are none.
- Type-check the payload before posting.
When it happens
Trigger: Posting outcome import data where :ratings is a hash, string, or single rating object instead of an array (e.g. ratings: {...} or ratings: 'none').
Common situations: Clients wrapping a single rating object without the array; JSON parsers turning a single-element collection into an object; template mix-ups sending a comma-separated string.
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
- invalid description value: #
- invalid ratings value: #
- Cannot change locked status on granular permission
- GUID is invalid: #
- Invalid action.
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/3ad2cf7ad6219325.
Report an issue: GitHub.
Appendix: source
Thrown at app/controllers/outcomes_academic_benchmark_import_api_controller.rb:111
end
end
def parse_int(value)
Integer value
rescue
raise "invalid value, must be integer: #{value}"
end
def valid_options(hash)
options = {}
if hash.key? :calculation_method
options[:calculation_method] = parse_calculation_method hash[:calculation_method]
options[:calculation_int] = parse_calculation_int options[:calculation_method], hash[:calculation_int]
end
options[:mastery_points] = parse_int hash[:mastery_points] if hash.key? :mastery_points
options[:points_possible] = parse_int hash[:points_possible] if hash.key? :points_possible
unless hash[:ratings].nil?
raise "ratings expected to be an array" unless hash[:ratings].is_a?(Array)
options[:ratings] = hash[:ratings].map { |r| parse_rating(r) }
end
options
end
def parse_calculation_method(value)
unless LearningOutcome.valid_calculation_method?(value)
raise "invalid calculation_method: #{value}"
end
value
end
def parse_calculation_int(calc_method, value)
int = value.nil? ? nil : parse_int(value)
unless LearningOutcome.valid_calculation_int?(int, calc_method)
raise "invalid calculation_int: #{value}"View on GitHub (pinned to 1c9f0bb801)