{"record":{"id":"8a88f8c6ff3de1f2","repo":"instructure/canvas-lms","slug":"missing-criteria-name-for-rubric-name","errorCode":null,"errorMessage":"Missing 'Criteria Name' for #{rubric_name}","messagePattern":"Missing 'Criteria Name' for #(.+?)","errorType":"validation","errorClass":"DataFormatError","httpStatus":null,"severity":"error","filePath":"app/models/rubric_import.rb","lineNumber":115,"sourceCode":"      track_error\n      job_failed!\n    end\n  end\n\n  def process_rubrics\n    rubrics_by_name = RubricCSVImporter.new(attachment).parse\n    raise DataFormatError, I18n.t(\"The file is empty or does not contain valid rubric data.\") if rubrics_by_name.empty?\n\n    total_rubrics = rubrics_by_name.keys.count\n    error_data = []\n\n    rubrics_by_name.each_with_index do |(rubric_name, rubric_data), rubric_index|\n      raise DataFormatError, I18n.t(\"Missing 'Rubric Name' in some rows.\") if rubric_name.blank?\n\n      rubric = context.rubrics.build(rubric_imports_id: id)\n      criteria_hash = {}\n      rubric_data.each_with_index do |criterion, criterion_index|\n        raise DataFormatError, \"Missing 'Criteria Name' for #{rubric_name}\" if criterion[:description].blank?\n        raise DataFormatError, \"Missing ratings for #{criterion[:description]}\" if criterion[:ratings].empty?\n\n        ratings_hash = {}\n        criterion[:ratings].each_with_index do |rating, rating_index|\n          ratings_hash[rating_index.to_s] = {\n            \"description\" => rating[:description],\n            \"long_description\" => rating[:long_description],\n            \"points\" => rating[:points]\n          }\n        end\n        criteria_hash[criterion_index.to_s] = {\n          \"description\" => criterion[:description],\n          \"long_description\" => criterion[:long_description],\n          \"ratings\" => ratings_hash\n        }\n        if context.root_account.feature_enabled?(:rubric_criterion_range)\n          criteria_hash[criterion_index.to_s][\"criterion_use_range\"] = criterion[:criterion_use_range]\n        end","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/rubric_import.rb#L97-L133","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Open the import file and fill in the missing 'Criteria Name' for every criterion row of the named rubric, then re-import.","Pre-validate the parsed rubric_data in the caller: reject rows with blank description before calling process_rubrics.","If rows are stray artifacts (e.g. trailing blanks), remove those rows from the import file.","If the file is generated programmatically, fix the generator to always emit a description per criterion."],"exampleFix":"// before\nrubric_data.each_with_index do |criterion, _i|\n  build_criterion(criterion) # raises at line 115 if description blank\nend\n\n// after\nrubric_data.each_with_index do |criterion, i|\n  if criterion[:description].blank?\n    raise DataFormatError, \"Missing 'Criteria Name' for #{rubric_name} (row #{i + 1})\"\n  end\n  build_criterion(criterion)\nend","handlingStrategy":"validation","validationCode":"bad = rubric_data.each_with_index.select { |c, _| c[:description].blank? }\nraise ArgumentError, \"blank criteria names for #{rubric_name}\" unless bad.empty?","typeGuard":"def valid_criterion?(c)\n  c.is_a?(Hash) && c[:description].present? && c[:ratings].is_a?(Array)\nend","tryCatchPattern":"begin\n  import.process_rubrics\nrescue DataFormatError => e\n  Rails.logger.warn(\"Rubric import rejected: #{e.message}\")\n  render json: { errors: [e.message] }, status: :unprocessable_entity\nend","preventionTips":["Validate every criterion row (description + ratings present) before calling process_rubrics.","Trim and re-check spreadsheet cells; empty-looking cells often contain whitespace.","Surface row numbers in your own pre-validation errors so users can fix CSVs quickly."],"tags":["rubric-import","validation","csv-import","data-format"],"backgroundTag":"empty-required-field","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"}