instructure/canvas-lms · error · DataFormatError

Missing 'Criteria Name' for #

Error message

Missing 'Criteria Name' for #{rubric_name}

What it means

RubricImport#process_rubrics groups imported rows by rubric name and iterates criteria per rubric. Each criterion row must carry a non-blank :description (its name); otherwise a DataFormatError is raised naming the rubric. It guards against building RubricCriterion records with empty descriptions, which Canvas does not allow.

Solutions

  1. Open the import file and fill in the missing 'Criteria Name' for every criterion row of the named rubric, then re-import.
  2. Pre-validate the parsed rubric_data in the caller: reject rows with blank description before calling process_rubrics.
  3. If rows are stray artifacts (e.g. trailing blanks), remove those rows from the import file.
  4. If the file is generated programmatically, fix the generator to always emit a description per criterion.

Example fix

// before
rubric_data.each_with_index do |criterion, _i|
  build_criterion(criterion) # raises at line 115 if description blank
end

// after
rubric_data.each_with_index do |criterion, i|
  if criterion[:description].blank?
    raise DataFormatError, "Missing 'Criteria Name' for #{rubric_name} (row #{i + 1})"
  end
  build_criterion(criterion)
end
Defensive patterns

Strategy: validation

Validate before calling

bad = rubric_data.each_with_index.select { |c, _| c[:description].blank? }
raise ArgumentError, "blank criteria names for #{rubric_name}" unless bad.empty?

Type guard

def valid_criterion?(c)
  c.is_a?(Hash) && c[:description].present? && c[:ratings].is_a?(Array)
end

Try / catch

begin
  import.process_rubrics
rescue DataFormatError => e
  Rails.logger.warn("Rubric import rejected: #{e.message}")
  render json: { errors: [e.message] }, status: :unprocessable_entity
end

Prevention

When it happens

Trigger: Call process_rubrics on a RubricImport whose parsed CSV/data contains a criterion row under some rubric_name where criterion[:description] is nil or empty string (e.g. a row with a rubric name but blank criteria name column).

Common situations: Importing a rubric CSV where the 'Criteria Name' (description) cell is empty for one or more rows; exporting/editing a spreadsheet and deleting the criteria column values but leaving rating columns; extra trailing rows with ratings but no criterion title.

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/8a88f8c6ff3de1f2. Report an issue: GitHub.

Appendix: source

Thrown at app/models/rubric_import.rb:115

      track_error
      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

View on GitHub (pinned to 1c9f0bb801)