instructure/canvas-lms · error · RuntimeError
# : #
Error message
#{description}: #{additional_info} What it means
Raised by OutcomesService::MigrationService#add_failed_import_warning when checking import status (import_completed?) determines the Outcomes Service import failed, after attaching a warning to the associated ContentMigration. The message combines a failure description with extra info (typically the error response body or status). It aborts the migration-check flow with the failure detail.
Solutions
- Read description/additional_info in the error for the underlying Outcomes Service failure
- Check the Outcomes Service logs for the import_id to see why the import failed
- Verify the content_imports status URL and that the service instance is healthy
- Re-run the outcome migration after fixing the payload or service-side error
- Ensure data[:content_migration] is set so the failure is recorded as a warning on the migration
Example fix
// before
raise "#{description}: #{additional_info}"
// after
if data.key?(:content_migration)
data[:content_migration].add_warning(I18n.t("%{desc} %{info}", desc: description, info: additional_info))
data[:content_migration].fail!
else
raise "#{description}: #{additional_info}"
end Defensive patterns
Strategy: try-catch
Validate before calling
import_data = { import_id:, course:, content_migration: }
return unless import_data.key?(:content_migration) && import_data[:content_migration].present? Type guard
valid = data.is_a?(Hash) && data.key?(:content_migration) && data[:import_id].present?
Try / catch
begin done = service.import_completed?(import_data) rescue RuntimeError => e import_data[:content_migration]&.add_warning(e.message) import_data[:content_migration]&.fail! end
Prevention
- Poll import status with exponential backoff to tolerate transient 5xx
- Verify import_id belongs to the correct Outcomes Service instance
- Always attach content_migration to import_data so failures become warnings, not raises
- Check Outcomes Service job logs for failed imports before re-running migrations
When it happens
Trigger: import_completed? receives a non-2xx response when GETting the content_import status URL, or the import JSON reports a failed/errored workflow_state, or the import_id cannot be resolved — then add_failed_import_warning is invoked with the description and additional_info.
Common situations: Outcomes Service import job failed server-side (bad content payload); import_id expired or belongs to a different service instance; transient 5xx while polling status; content_migration association missing so the warning path throws instead of only warning.
Related errors
- Content Export for Outcomes Service failed
- Error parsing JSON results from Outcomes Service: #
- Error queueing export for Outcomes Service: #
- Error retrieving export for Outcomes Service: #
- Error retrieving export state for Outcomes Service: #
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/b22960a9395497b3.
Report an issue: GitHub.
Appendix: source
Thrown at app/models/outcomes_service/migration_service.rb:156
true
when "failed"
failure_desc = "Content Import for Outcomes Service failed"
add_failed_import_warning(import_data, failure_desc, json.to_s)
else
false
end
else
failure_desc = "Error retrieving import state for Outcomes Service: #{response.body}"
add_failed_import_warning(import_data, failure_desc)
end
end
private
def add_failed_import_warning(data, description, additional_info = "")
data[:content_migration].add_warning(I18n.t("%{desc}", desc: description)) if data.key?(:content_migration)
if additional_info.present?
raise "#{description}: #{additional_info}"
else
raise description
end
end
def lookup_artifact(artifact_type, artifact_id, course)
case artifact_type
when "canvas.page"
course.wiki_pages.where(id: artifact_id).first
end
end
def headers_for(course, scope, overrides = {})
{
"Authorization" => OutcomesService::Service.jwt(course, scope, overrides:)
}
end
View on GitHub (pinned to 1c9f0bb801)