{"record":{"id":"360f0b1cdc2f12dc","repo":"instructure/canvas-lms","slug":"invalid-fields-for-an-outcome-invalid","errorCode":null,"errorMessage":"Invalid fields for an outcome: %{invalid}","messagePattern":"Invalid fields for an outcome: %(.+?)","errorType":"exception","errorClass":"InvalidDataError","httpStatus":null,"severity":"error","filePath":"lib/outcomes/import.rb","lineNumber":146,"sourceCode":"      model.description = group[:description] || \"\"\n      model.workflow_state = group[:workflow_state].presence || \"active\"\n      model.learning_outcome_group = parent\n      model.outcome_import_id = outcome_import_id\n      model.save!\n\n      if model.workflow_state == \"deleted\"\n        model.destroy!\n      end\n\n      model\n    end\n\n    def import_outcome(outcome)\n      invalid = outcome.keys.select do |k|\n        outcome[k].present? && GROUP_ONLY_FIELDS.include?(k)\n      end\n      if invalid.present?\n        raise InvalidDataError, I18n.t(\n          \"Invalid fields for an outcome: %{invalid}\",\n          invalid: invalid.map(&:to_s).inspect\n        )\n      end\n\n      model = find_prior_outcome(outcome)\n      model.context = context if model.new_record?\n\n      unless child_context?(context, of: model.context)\n        raise InvalidDataError, I18n.t(\n          \"Outcome with ID %{guid} already exists in another unrelated course or account (%{name})\",\n          guid: outcome[:vendor_guid],\n          name: model.context.name\n        )\n      end\n\n      allow_indirect = outcome.key?(:course_id)\n      parents = find_parents(outcome, context, allow_indirect:)","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/lib/outcomes/import.rb#L128-L164","documentation":"import_outcome rejects outcome objects carrying group-only fields: course_id (GROUP_ONLY_FIELDS). If course_id is present with a non-blank value on an object_type 'outcome' row, the import aborts listing the offending keys. Outcome rows always import into the import context; they cannot re-target courses.","triggerScenarios":"Calling import_object with {object_type: 'outcome', course_id: 42, ...}; reusing an account-level group schema (which supports course_id) for outcome rows.","commonSituations":"Single combined CSV where every row includes a course_id column; templated payloads that copy group fields onto outcomes; wanting to import the same outcome into many courses and mistakenly adding course_id per row.","solutions":["Remove course_id from outcome objects and import with the intended Course or Account context instead.","Split the file per target course and run one import per course context.","Blank out course_id (nil or '') for outcome rows in shared-schema files — only present? values trigger the error."],"exampleFix":"// before\n{ object_type: 'outcome', vendor_guid: 'o1', course_id: 42, ... }\n// after\n{ object_type: 'outcome', vendor_guid: 'o1', ... } # run import with course context if needed","handlingStrategy":"validation","validationCode":"if outcome[:object_type] == 'outcome' && outcome[:course_id].present?\n  raise ArgumentError, \"outcome rows cannot set course_id\"\nend","typeGuard":"def outcome_only_valid?(obj)\n  obj.is_a?(Hash) && !%i[course_id].any? { |k| obj[k].present? }\nend","tryCatchPattern":"begin\n  importer.import_object(outcome)\nrescue Outcomes::Import::InvalidDataError => e\n  Rails.logger.warn(\"bad outcome row #{outcome[:vendor_guid]}: #{e.message}\")\nend","preventionTips":["Strip course_id from outcome rows in shared-schema files","Run one import per course context instead of per-row targeting","Validate object_type-specific allowed keys before import"],"tags":["validation","schema","outcomes-import","payload"],"backgroundTag":"schema-validation-failed","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"}