instructure/canvas-lms · error · CCImportError
Invalid XML Configuration
Error message
Invalid XML Configuration
What it means
convert_blti_xml validates that the parsed BLTI/LTI configuration XML carries an imsglobal namespace before importing. If the parsed document's namespaces do not include 'imsglobal', the XML is not recognized as a valid LTI tool configuration and a CCImportError is raised.
Solutions
- Inspect the fetched XML and ensure the root element declares an imsglobal namespace (e.g. <basic_lti_link xmlns="http://www.imsglobal.org/xsd/imslticc_v1p0">)
- Fetch the configuration XML manually (curl) and confirm the tool provider is returning real LTI config, not an error/login page
- Obtain a fresh/correct configuration XML URL from the tool vendor
Example fix
# before (no namespace)
<cartridge_basiclti_link>
...
</cartridge_basiclti_link>
# after
<cartridge_basiclti_link xmlns="http://www.imsglobal.org/xsd/imslticc_v1p0"
xmlns:blti="http://www.imsglobal.org/xsd/imsbasiclti_v1p0">
...
</cartridge_basiclti_link> Defensive patterns
Strategy: validation
Validate before calling
doc = Nokogiri::XML(xml)
raise CCImportError, 'not LTI config' unless doc.namespaces.any? { |_, v| v.downcase.include?('imsglobal') } Type guard
def lti_config_xml?(xml)
doc = Nokogiri::XML(xml) { |c| c.norecover }
doc.namespaces.values.join.downcase.include?('imsglobal')
rescue Nokogiri::XML::SyntaxError
false
end Try / catch
begin
tool = converter.convert_blti_xml(xml)
rescue CCImportError => e
Rails.logger.warn("BLTI import rejected: #{e.message}")
flash[:error] = I18n.t('invalid_tool_config')
end Prevention
- Validate the namespace before calling convert_blti_xml
- Prefer obtaining config XML via the vendor's official config URL
- Check response content-type before treating an HTTP body as LTI XML
When it happens
Trigger: Calling convert_blti_xml (directly or via retrieve_and_convert_blti_url) with XML whose root/declared namespaces lack 'imsglobal' — e.g. plain XML, wrong namespace URI, or an HTML error page that happens to parse as XML.
Common situations: A tool provider URL returns a non-LTI XML document or error page; the config XML was hand-edited dropping the xmlns declaration; the vendor uses an outdated/incorrect namespace; the fetched content is a login/redirect page.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Invalid url in xml. Ampersands must be escaped.
- e.message
- EventType # is invalid
- Friendly description is too long (maximum is 255 characters)
- Invalid fields after ratings
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/89b27929c10603cd.
Report an issue: GitHub.
Appendix: source
Thrown at lib/cc/importer/blti_converter.rb:113
if (tool[:assignment_points_possible] = ext[:custom_fields].delete("outcome"))
tool[:assignment_points_possible] = tool[:assignment_points_possible].to_f
end
tool[:settings] = ext[:custom_fields]
else
tool[:extensions] << ext
end
end
if (icon = get_node_val(doc, "#{link_css_path} > #{blti}|icon"))
tool[:settings] ||= {}
tool[:settings][:icon_url] = icon.strip
end
tool
end
def convert_blti_xml(xml)
doc = create_xml_doc(xml)
unless doc.namespaces.to_s.downcase.include? "imsglobal"
raise CCImportError, I18n.t("Invalid XML Configuration")
end
begin
tool = convert_blti_link(doc)
check_for_unescaped_url_properties(tool) if tool
rescue Nokogiri::XML::XPath::SyntaxError
raise CCImportError, I18n.t(:invalid_xml_syntax, "Invalid xml syntax")
end
tool
end
def check_for_unescaped_url_properties(obj)
# Recursively look for properties named 'url'
case obj
when Hash
obj.select { |k, v| k.to_s == "url" && v.is_a?(String) }
.each_value { |v| check_for_unescaped_url(v) }
obj.each_value { |v| check_for_unescaped_url_properties(v) }View on GitHub (pinned to 1c9f0bb801)