{"record":{"id":"6f3bdd56cab76d47","repo":"instructure/canvas-lms","slug":"error-message-wiki-pages-api-controller","errorCode":null,"errorMessage":"error.message","messagePattern":"error\\.message","errorType":"http","errorClass":null,"httpStatus":503,"severity":"error","filePath":"app/controllers/wiki_pages_api_controller.rb","lineNumber":947,"sourceCode":"  private\n\n  def ai_alt_text_params_valid?\n    return false if params[:attachment_id].blank?\n\n    true\n  end\n\n  def rescue_unparsable_content(error)\n    @page.errors.add(:body, error.message) if @page.present?\n\n    render json: @page&.errors || {}, status: :bad_request\n  end\n\n  def rescue_content_service_error(error)\n    error_report = ErrorReport.log_error(\n      \"content_service_client_error\",\n      { message: error.message, service_errors: error.service_errors }\n    )\n    render json: { error: error.message, error_report_id: error_report.id }, status: :service_unavailable\n  end\n\n  def create_external_content_ref\n    return unless @context.account.horizon_block_content_editor?\n\n    @page.create_block_editor_data(user_uuid: @current_user.uuid, data: @block_editor_data)\n  end\n\n  def update_external_content_ref\n    return unless @context.account.horizon_block_content_editor?\n\n    @page.update_block_editor_data(user_uuid: @current_user.uuid, data: @block_editor_data)\n  end\n\n  def extract_block_editor_data\n    return unless params[:wiki_page] && @context.account.horizon_block_content_editor?\n","sourceCodeStart":929,"sourceCodeEnd":965,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/controllers/wiki_pages_api_controller.rb#L929-L965","documentation":"rescue_content_service_error handles exceptions bubbling out of the content-service client (used by wiki page create/show/update). It logs an ErrorReport tagged 'content_service_client_error' (with the upstream service's error messages) and renders {\"error\": error.message, \"error_report_id\": ...} with HTTP 503 Service Unavailable. A 503 here means Canvas could not complete the operation because the external content service (e.g. Horizon block content processing) is unavailable or returned errors — the problem is upstream, not with the wiki page itself.","triggerScenarios":"Creating, showing, or updating a wiki page in an account with the horizon block content editor enabled (create_external_content_ref), where the call to the external content service raises an error carrying .service_errors — service outage, network failure, timeout, or the service rejecting the submitted content.","commonSituations":"Horizon/content-service deployment down or being upgraded; network/firewall blocking Canvas→service traffic; service returning 4xx/5xx because the page HTML contains unsupported content; environment misconfiguration of the content service URL or credentials after a deploy.","solutions":["Look up error_report_id from the response in Canvas admin Error Reports — the stored message and service_errors detail what the upstream service reported.","Check the content service's health/status endpoint and its logs; retry the page operation once the service recovers.","Verify the content service URL/credentials configuration in this Canvas environment after any deploy or config change.","If the service rejects specific page content, simplify or remove the offending HTML block and retry the save."],"exampleFix":"// before: assuming page save failure means invalid page data\nif (res.status === 503) alert('Invalid page content');\n// after: treat 503 as upstream outage and surface the report id\nif (res.status === 503) {\n  const body = await res.json();\n  showError(`Content service temporarily unavailable (report ${body.error_report_id}). Try again later.`);\n}","handlingStrategy":"retry","validationCode":"// before saving a page in a horizon_block_content_editor? account\nconst serviceHealthy = await fetch(contentServiceHealthUrl).then(r => r.ok).catch(() => false);\nif (!serviceHealthy) queueSaveForRetry(page);","typeGuard":"function isContentServiceError(e) {\n  return e instanceof Error && Array.isArray(e.service_errors);\n}","tryCatchPattern":"try {\n  const page = await api.createWikiPage(payload);\n} catch (e) {\n  if (isContentServiceError(e)) {\n    // e.name === 'content_service_client_error' in ErrorReports; HTTP 503 with error_report_id\n    await retryWithBackoff(() => api.createWikiPage(payload), { maxAttempts: 3 });\n  } else {\n    throw e;\n  }\n}","preventionTips":["Treat any 503 on wiki page create/show/update as transient upstream failure and retry with exponential backoff.","Persist the returned error_report_id so support can correlate with Canvas Error Reports.","Monitor content-service health before enabling horizon_block_content_editor in an account.","Validate page HTML against content-service supported-block rules client-side before submitting."],"tags":["upstream-service","http-503","wiki-pages","content-service","service-unavailable"],"backgroundTag":"upstream-api-error","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"}