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

  1. Add at least one rating (description + points) under the named criterion in the import file and re-import.
  2. Fix the parsing step so rating rows are correctly attached to their parent criterion instead of landing in another criterion's array.
  3. 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

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


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
      end

View on GitHub (pinned to 1c9f0bb801)