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

  1. Fetch the metadata again from the IdP and confirm it is valid XML before saving
  2. Validate the XML against SAML metadata schema (xmllint with the metadata XSD) to find the offending elements
  3. 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

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


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.value

View on GitHub (pinned to 1c9f0bb801)