instructure/canvas-lms · error · ParseError
Invalid fields
Error message
Invalid fields: %{fields} What it means
Raised by Outcomes::CsvImporter#validate_headers when the header row contains fields that are neither in REQUIRED_FIELDS nor OPTIONAL_FIELDS. The importer whitelists headers; any unrecognized column name before 'ratings' triggers this ParseError listing the invalid fields. This prevents silently ignoring typo'd or unsupported columns.
Solutions
- Remove or rename the offending columns listed in the error to match the allowed field names exactly.
- Compare your headers against the template's valid fields (REQUIRED_FIELDS + OPTIONAL_FIELDS) and fix typos.
- Split data that does not belong in this import into a separate process instead of adding extra columns.
Example fix
// before vendor_guid,title,display_name,ratings // after vendor_guid,title,ratings
Defensive patterns
Strategy: validation
Validate before calling
ALLOWED = REQUIRED_FIELDS + OPTIONAL_FIELDS
headers = CSV.open(path, &:first).map(&:to_sym)
invalid = headers - ALLOWED
raise "unknown columns: #{invalid.inspect}" unless invalid.empty? Try / catch
begin importer.parse_file rescue Outcomes::CsvImporter::ParseError => e log_and_report(e.message) # list invalid fields to the uploader end
Prevention
- Keep extra data out of the import CSV — only whitelisted columns
- Spell-check header names against the template
- Re-derive headers from the template after any manual edit
When it happens
Trigger: Header containing a typo such as 'vendor_Guid' or 'titel'; an extra column like 'display_name' that is not in the whitelist; copy-pasting headers from a different import format with extra columns.
Common situations: Migrating CSVs from another LMS with different column names; manual edits introducing typos; older/newer template versions whose headers no longer match this importer's whitelist.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Invalid fields after ratings
- Friendly description is too long (maximum is 255 characters)
- Invalid value for
- Missing required fields
- Missing 'Rubric Name' in some rows.
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/e79df189c27bb058.
Report an issue: GitHub.
Appendix: source
Thrown at lib/outcomes/csv_importer.rb:149
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 > 255
raise InvalidDataError, I18n.t("Friendly description is too long (maximum is 255 characters)")
end
View on GitHub (pinned to 1c9f0bb801)