instructure/canvas-lms · error
Invalid schema
Error message
Invalid schema
What it means
populate_from_metadata_xml parses the supplied XML with SAML2::Entity.parse and raises "Invalid schema" when parsing yields nil or the entity fails valid_schema?. The metadata XML does not conform to SAML metadata XSD.
Solutions
- Fetch the metadata again from the IdP and confirm it is valid XML before saving
- Validate the XML against SAML metadata schema (xmllint with the metadata XSD) to find the offending elements
- Check that the metadata URL is the correct SAML metadata endpoint, not an HTML page
Example fix
# before provider.populate_from_metadata_xml(response.body) # after entity = SAML2::Entity.parse(response.body) raise 'bad metadata' unless entity&.valid_schema? provider.populate_from_metadata_xml(response.body)
Defensive patterns
Strategy: validation
Validate before calling
xml = URI.parse(metadata_url).read
raise 'not xml' unless xml.lstrip.start_with?('<?xml', '<')
raise 'invalid schema' unless SAML2::Entity.parse(xml)&.valid_schema? Type guard
null
Try / catch
begin
provider.populate_from_metadata_url(url)
rescue RuntimeError => e
raise e unless e.message == 'Invalid schema'
Rails.logger.error("SAML metadata from #{url} is not schema-valid")
end Prevention
- Verify the metadata URL returns XML, not an HTML error page
- Validate metadata against the SAML metadata XSD before saving
- Re-download metadata after IdP upgrades
When it happens
Trigger: Calling populate_from_metadata_xml with malformed XML, truncated XML, or well-formed XML that violates SAML metadata schema; also when populate_from_metadata_url downloads non-XML content (HTML error page) and passes it through.
Common situations: IdP metadata URL returns an HTML login/error page; XML pasted with copy/paste corruption or extra text; IdP upgraded and publishes schema-invalid metadata; wrong URL used for metadata.
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
- Must be a single Entity
- Must provide exactly one IDPSSODescriptor; found #
- A new_id, '# ', referenced an existing # and the # with #…
- A new_integration_id, '#
- A student referenced a non-existent user #
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/8bd606ac0edf5d7b.
Report an issue: GitHub.
Appendix: source
Thrown at app/models/authentication_provider/saml.rb:329
end
settings[:signing_certificates] = idp.signing_keys.filter_map(&:x509)
settings[:signing_keys] = idp.signing_keys.filter_map(&:key).map(&:to_s)
case idp.want_authn_requests_signed?
when true
# use ||= to not overwrite a specific algorithm that has otherwise been
# chosen
self.sig_alg ||= "RSA-SHA1"
when false
self.sig_alg = nil
# else nil
# don't change the user settings
end
end
def populate_from_metadata_xml(xml, source: "manual")
entity = SAML2::Entity.parse(xml)
raise "Invalid schema" unless entity&.valid_schema?
if entity.is_a?(SAML2::Entity::Group) && idp_entity_id.present?
entity = entity.find { |e| e.entity_id == idp_entity_id }
end
raise "Must be a single Entity" unless entity.is_a?(SAML2::Entity)
populate_from_metadata(entity)
# Only set this after all the above runs so that we catch any issues before overwriting the cached metadata
settings["metadata"] = xml
settings["metadata_source"] = source
end
alias_method :metadata=, :populate_from_metadata_xml
def populate_from_metadata_url(url)
::Canvas.timeout_protection("saml_metadata_fetch") do
CanvasHttp.get(url) do |response|
# raise error unless it's a 2xx
response.valueView on GitHub (pinned to 1c9f0bb801)