instructure/canvas-lms · error
error.message
Error message
error.message
What it means
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.
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.
Example fix
// before: assuming page save failure means invalid page data
if (res.status === 503) alert('Invalid page content');
// after: treat 503 as upstream outage and surface the report id
if (res.status === 503) {
const body = await res.json();
showError(`Content service temporarily unavailable (report ${body.error_report_id}). Try again later.`);
} Defensive patterns
Strategy: retry
Validate before calling
// before saving a page in a horizon_block_content_editor? account const serviceHealthy = await fetch(contentServiceHealthUrl).then(r => r.ok).catch(() => false); if (!serviceHealthy) queueSaveForRetry(page);
Type guard
function isContentServiceError(e) {
return e instanceof Error && Array.isArray(e.service_errors);
} Try / catch
try {
const page = await api.createWikiPage(payload);
} catch (e) {
if (isContentServiceError(e)) {
// e.name === 'content_service_client_error' in ErrorReports; HTTP 503 with error_report_id
await retryWithBackoff(() => api.createWikiPage(payload), { maxAttempts: 3 });
} else {
throw e;
}
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/6f3bdd56cab76d47.
Report an issue: GitHub.
Appendix: source
Thrown at app/controllers/wiki_pages_api_controller.rb:947
private
def ai_alt_text_params_valid?
return false if params[:attachment_id].blank?
true
end
def rescue_unparsable_content(error)
@page.errors.add(:body, error.message) if @page.present?
render json: @page&.errors || {}, status: :bad_request
end
def rescue_content_service_error(error)
error_report = ErrorReport.log_error(
"content_service_client_error",
{ message: error.message, service_errors: error.service_errors }
)
render json: { error: error.message, error_report_id: error_report.id }, status: :service_unavailable
end
def create_external_content_ref
return unless @context.account.horizon_block_content_editor?
@page.create_block_editor_data(user_uuid: @current_user.uuid, data: @block_editor_data)
end
def update_external_content_ref
return unless @context.account.horizon_block_content_editor?
@page.update_block_editor_data(user_uuid: @current_user.uuid, data: @block_editor_data)
end
def extract_block_editor_data
return unless params[:wiki_page] && @context.account.horizon_block_content_editor?
View on GitHub (pinned to 1c9f0bb801)