instructure/canvas-lms · error · RuntimeError

Error retrieving export for Outcomes Service: #

Error message

Error retrieving export for Outcomes Service: #{response.body}

What it means

Guard in OutcomesService::MigrationService#retrieve_export: the HTTP GET to the Outcomes Service content_exports API returned a non-2xx response, so this error is raised embedding the response body — the export could not be retrieved from the remote service.

Solutions

  1. Inspect the embedded response body for the HTTP status cause
  2. Refresh/verify JWT in headers_for for scope 'content_migration.export'
  3. Confirm export_id/course match what begin_export returned
  4. Retry retrieval once the service is healthy
Defensive patterns

Strategy: retry

Try / catch

begin
  data = MigrationService.retrieve_export(export_data)
rescue RuntimeError => e
  raise unless e.message.start_with?('Error retrieving export')
  attempts += 1
  retry if attempts < 3
  Canvas::Errors.capture(e)
end

Prevention

When it happens

Trigger: Fetching /api/content_exports/:id after export completion returns 4xx/5xx — bad or expired auth headers, wrong export id, or service error.

Common situations: Long-running exports whose JWT expires before retrieval; misconfigured service URL; remote service instability.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/c333031318b8c845. Report an issue: GitHub.

Appendix: source

Thrown at app/models/outcomes_service/migration_service.rb:86

          else
            false
          end
        else
          raise "Error retrieving export state for Outcomes Service: #{response.body}"
        end
      end

      def retrieve_export(export_data)
        content_export_url = "#{OutcomesService::Service.url(export_data[:course])}/api/content_exports/#{export_data[:export_id]}"
        response = CanvasHttp.get(
          content_export_url,
          headers_for(export_data[:course], "content_migration.export", id: export_data[:export_id])
        )
        if /^2/.match?(response.code.to_s)
          json = JSON.parse(response.body)
          json["data"]
        else
          raise "Error retrieving export for Outcomes Service: #{response.body}"
        end
      end

      def send_imported_content(course, content_migration, imported_content)
        content_imports_url = "#{OutcomesService::Service.url(course)}/api/content_imports"
        data = imported_content.merge(
          context_type: "course",
          context_id: course.id.to_s,
          external_migration_id: content_migration.id
        )
        extractor = OutcomesService::MigrationExtractor.new(content_migration)
        data = data.merge(
          outcomes: extractor.learning_outcomes(course),
          groups: extractor.learning_outcome_groups(course),
          edges: extractor.learning_outcome_links
        )
        response = CanvasHttp.post(
          content_imports_url,

View on GitHub (pinned to 1c9f0bb801)