{"record":{"id":"9a29ebb347c99b25","repo":"instructure/canvas-lms","slug":"youtube-scan-retry-timed-out-scan-id-progress-id-course-id","errorCode":null,"errorMessage":"[YouTube Scan Retry] Timed out scan_id=#{progress.id}, course_id=#{progress.context_id}","messagePattern":"\\[YouTube Scan Retry\\] Timed out scan_id=#(.+?), course_id=#(.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"app/services/youtube_migration_service.rb","lineNumber":838,"sourceCode":"\n    progress.set_results(results)\n\n    call_external_tool(progress.context, progress.id)\n\n    Rails.logger.info(\"[YouTube Scan Retry] Re-emitted Live Event for scan_id=#{progress.id}, course_id=#{progress.context_id}, retry_count=#{results[:retry_count]}\")\n  end\n\n  def self.timeout_scan(progress)\n    results = (progress.results || {}).dup\n    results[:new_quizzes_scan_status] = \"timeout\"\n    results[:error] = \"Timed out waiting for New Quizzes scan results after 3 hours\"\n    results[:completed_at] = Time.now.utc\n    results[:timeout_at] = Time.now.utc\n\n    progress.set_results(results)\n    progress.complete!\n\n    Rails.logger.warn(\"[YouTube Scan Retry] Timed out scan_id=#{progress.id}, course_id=#{progress.context_id}\")\n  end\nend\n","sourceCodeStart":820,"sourceCodeEnd":841,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/services/youtube_migration_service.rb#L820-L841","documentation":"YoutubeMigrationService performs YouTube link scans with a bounded wait; when a scan exceeds its deadline, the service finalizes the Progress object with timeout results, marks it complete, and logs this warning. The scan did not finish in time, but the job ends cleanly instead of hanging.","triggerScenarios":"A YouTube scan tracked by a Progress record (progress.id) for a course (progress.context_id) runs past the scan's timeout threshold — e.g., many YouTube links to validate or YouTube API calls hanging — so the timeout branch sets results[:timeout_at], calls progress.complete!, and logs this message.","commonSituations":"Course migrations with hundreds of embedded YouTube links; YouTube API slowness or outages; network egress restrictions in the job container causing HTTP calls to hang until the deadline.","solutions":["Re-run the scan for the course once YouTube/network conditions are healthy","Increase the scan timeout or add per-link timeouts so slow links don't consume the whole budget","Check YouTube API availability/quota for the period the scan ran","Batch very large courses into smaller scans to stay within the deadline"],"exampleFix":"// before\n# one big scan with fixed timeout -> timeouts on large courses\nservice.scan(course)\n// after\nservice.scan(course, batch_size: 50) # smaller batches, per-link timeouts\n","handlingStrategy":"retry","validationCode":"# before scanning, cheaply count links to size the timeout budget\nlink_count = course.youtube_links.count\nraise ScanBudgetExceeded if link_count > MAX_LINKS_PER_SCAN","typeGuard":null,"tryCatchPattern":"begin\n  YoutubeMigrationService.scan(course)\nrescue Timeout::Error\n  # or detect progress results[:timeout_at]\n  schedule_rescan(course, smaller_batch: true)\nend","preventionTips":["Size scan timeouts proportional to link count","Add per-request HTTP timeouts so one link can't consume the budget","Re-queue timed-out scans automatically with smaller batches"],"tags":["timeout","youtube","migration","background-job"],"backgroundTag":"request-timeout","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"}