instructure/canvas-lms · error · DataFormatError
Missing ratings for #
Error message
Missing ratings for #{criterion[:description]} What it means
RubricImport#process_rubrics requires every criterion to have at least one rating; a criterion with criterion[:ratings] empty cannot form a valid rubric criterion, so a DataFormatError is raised referencing the criterion description. Canvas rubrics model all scoring through ratings, so an empty ratings array is invalid.
Solutions
- Add at least one rating (description + points) under the named criterion in the import file and re-import.
- Fix the parsing step so rating rows are correctly attached to their parent criterion instead of landing in another criterion's array.
- Pre-validate rubric_data in the caller and reject criteria with empty ratings before process_rubrics runs.
Example fix
// before
criterion = { description: 'Quality', ratings: [] }
import.process_rubrics # => DataFormatError: Missing ratings for Quality
// after
criterion = { description: 'Quality', ratings: [{ description: 'Excellent', points: 10 }, { description: 'Poor', points: 0 }] }
import.process_rubrics # succeeds Defensive patterns
Strategy: validation
Validate before calling
missing = rubric_data.reject { |c| c[:ratings].is_a?(Array) && c[:ratings].any? }
raise ArgumentError, "criteria without ratings: #{missing.map { |c| c[:description] }.join(', ')}" if missing.any? Type guard
def has_ratings?(criterion) criterion[:ratings].is_a?(Array) && !criterion[:ratings].empty? end
Try / catch
begin import.process_rubrics rescue DataFormatError => e flash[:error] = e.message redirect_to rubric_import_path(import) end
Prevention
- Ensure each criterion in the import file has at least one rating row beneath it.
- Verify CSV parsing attaches rating rows to the correct parent criterion.
- Run a dry-run parse of the file and dump criteria/ratings counts before importing.
When it happens
Trigger: Call process_rubrics where a criterion row has a description but its parsed :ratings array is empty or missing (no rating rows under that criterion in the import data).
Common situations: CSV import where a criterion row exists but its rating rows were deleted or misaligned (e.g. rating columns moved to another criterion); hand-built import hashes forgetting the ratings key; spreadsheet filters hiding rating rows on export.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Missing 'Criteria Name' for #
- Improper status "# " for abstract course #
- Improper status "# " for # # , skipping
- invalid description value: #
- invalid ratings value: #
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/95ac2b631bc61cc9.
Report an issue: GitHub.
Appendix: source
Thrown at app/models/rubric_import.rb:116
job_failed!
end
end
def process_rubrics
rubrics_by_name = RubricCSVImporter.new(attachment).parse
raise DataFormatError, I18n.t("The file is empty or does not contain valid rubric data.") if rubrics_by_name.empty?
total_rubrics = rubrics_by_name.keys.count
error_data = []
rubrics_by_name.each_with_index do |(rubric_name, rubric_data), rubric_index|
raise DataFormatError, I18n.t("Missing 'Rubric Name' in some rows.") if rubric_name.blank?
rubric = context.rubrics.build(rubric_imports_id: id)
criteria_hash = {}
rubric_data.each_with_index do |criterion, criterion_index|
raise DataFormatError, "Missing 'Criteria Name' for #{rubric_name}" if criterion[:description].blank?
raise DataFormatError, "Missing ratings for #{criterion[:description]}" if criterion[:ratings].empty?
ratings_hash = {}
criterion[:ratings].each_with_index do |rating, rating_index|
ratings_hash[rating_index.to_s] = {
"description" => rating[:description],
"long_description" => rating[:long_description],
"points" => rating[:points]
}
end
criteria_hash[criterion_index.to_s] = {
"description" => criterion[:description],
"long_description" => criterion[:long_description],
"ratings" => ratings_hash
}
if context.root_account.feature_enabled?(:rubric_criterion_range)
criteria_hash[criterion_index.to_s]["criterion_use_range"] = criterion[:criterion_use_range]
end
endView on GitHub (pinned to 1c9f0bb801)