instructure/canvas-lms · error · ParseError
Missing required fields
Error message
Missing required fields: %{fields} What it means
Raised by Outcomes::CsvImporter#validate_headers when one or more of the REQUIRED_FIELDS (vendor_guid, title, etc.) are absent from the header row before the 'ratings' column. The importer computes the set difference REQUIRED_FIELDS - headers and fails with a ParseError listing the missing fields. It guarantees every imported outcome row has the mandatory columns available.
Solutions
- Add the missing columns named in the error message (e.g. vendor_guid) to the header row before 'ratings'.
- Start from the official import template to guarantee the required header set.
- Check exact spelling/casing of headers — they must match REQUIRED_FIELDS exactly, e.g. 'vendor_guid', 'title'.
Example fix
// before title,description,ratings // after vendor_guid,title,description,ratings
Defensive patterns
Strategy: validation
Validate before calling
REQUIRED = %w[vendor_guid title description ratings]
headers = CSV.open(path, &:first).compact
missing = REQUIRED - headers
raise "missing columns: #{missing.join(', ')}" unless missing.empty? Try / catch
begin importer.parse_file rescue Outcomes::CsvImporter::ParseError => e show_template_error(e.message) # e.g. 'Missing required fields: ["vendor_guid"]' end
Prevention
- Start every import from the official template
- Check exact header spelling and casing
- Script a header check (REQUIRED_FIELDS - headers) before importing
When it happens
Trigger: A header row like `title,description,ratings` omitting `vendor_guid`; renamed headers (e.g. 'Title' with different casing is not matched, since matching is exact on the downcased symbol); truncated or reordered template where a required column was deleted.
Common situations: Using a hand-built CSV that forgot the vendor_guid column; editing the template and accidentally deleting a required column; exporting from a system whose column names differ from Canvas's expected ones.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/e352543b228f57c4.
Report an issue: GitHub.
Appendix: source
Thrown at lib/outcomes/csv_importer.rb:146
def check_encoding(str)
encoded = str&.force_encoding("utf-8")
valid = (encoded || "").valid_encoding?
raise ParseError, I18n.t("Not a valid utf-8 string: %{string}", string: str.inspect) unless valid
encoded
end
def validate_headers(row, _index)
main_columns_end = row.find_index("ratings") || row.length
headers = row.slice(0, main_columns_end).map(&:to_sym)
after_ratings = row[(main_columns_end + 1)..] || []
after_ratings = after_ratings.compact_blank.map(&:to_s)
raise ParseError, I18n.t("Invalid fields after ratings: %{fields}", fields: after_ratings.inspect) unless after_ratings.empty?
missing = (REQUIRED_FIELDS - headers).map(&:to_s)
raise ParseError, I18n.t("Missing required fields: %{fields}", fields: missing.inspect) unless missing.empty?
invalid = (headers - OPTIONAL_FIELDS - REQUIRED_FIELDS).map(&:to_s)
raise ParseError, I18n.t("Invalid fields: %{fields}", fields: invalid.inspect) unless invalid.empty?
headers
end
def import_row(headers, row)
simple = headers.zip(row).to_h
ratings = row[headers.length..]
object = simple.to_h
object[:ratings] = parse_ratings(ratings)
object[:learning_outcome_group_id] = @import[:learning_outcome_group_id]
if object[:mastery_points].present?
object[:mastery_points] = strict_parse_float(object[:mastery_points], I18n.t("mastery points"))
end
if object[:friendly_description].present? && object[:friendly_description].length > 255View on GitHub (pinned to 1c9f0bb801)