twentyhq/twenty · error · Error

KeyInfo element is missing

Error message

KeyInfo element is missing

What it means

Thrown when a KeyDescriptor element was found inside IDPSSODescriptor but it has no XMLDSig <KeyInfo> child element. KeyInfo is the standard wrapper (under the ds/dsig namespace) holding the <X509Data>. Without it the parser cannot reach the certificate.

Source

Thrown at packages/twenty-front/src/modules/settings/security/utils/parseSAMLMetadataFromXMLFile.ts:85

    const parser = new DOMParser();
    const xmlDoc = parser.parseFromString(xmlString, 'application/xml');
    if (xmlDoc.getElementsByTagName('parsererror').length > 0) {
      throw new Error('File is not valid XML');
    }

    const entityDescriptor = getByPrefixAndKey(xmlDoc, 'EntityDescriptor');
    if (!entityDescriptor)
      throw new Error('EntityDescriptor element is missing');

    const IDPSSODescriptor = getByPrefixAndKey(xmlDoc, 'IDPSSODescriptor');
    if (!IDPSSODescriptor)
      throw new Error('IDPSSODescriptor element is missing');

    const keyDescriptors = getByPrefixAndKey(IDPSSODescriptor, 'KeyDescriptor');
    if (!keyDescriptors) throw new Error('KeyDescriptor element is missing');

    const keyInfo = getByPrefixAndKey(keyDescriptors, 'KeyInfo');
    if (!keyInfo) throw new Error('KeyInfo element is missing');

    const x509Data = getByPrefixAndKey(keyInfo, 'X509Data');
    if (!x509Data) throw new Error('X509Data element is missing');

    const x509Certificate = getByPrefixAndKey(
      x509Data,
      'X509Certificate',
    )?.textContent?.trim();
    if (!x509Certificate)
      throw new Error('X509Certificate is missing or empty');

    const singleSignOnServices = getAllByPrefixAndKey(
      IDPSSODescriptor,
      'SingleSignOnService',
    ).map((service) => ({
      binding: service.getAttribute('Binding'),
      location: service.getAttribute('Location'),
    }));

View on GitHub (pinned to 1f5dd2bbd2)

Solutions

  1. Inspect the KeyDescriptor in the uploaded XML and confirm a <KeyInfo> child is present.
  2. Ensure the KeyInfo element uses the ds/dsig (or md/ns0/ns2) prefix that the parser recognizes.
  3. Re-download the metadata XML directly from the IdP to avoid truncation.

Example fix

// before: <md:KeyDescriptor use="encryption"><xenc:EncryptionMethod .../></md:KeyDescriptor>  (no KeyInfo)
// after:  <md:KeyDescriptor use="signing"><ds:KeyInfo><ds:X509Data>...</ds:X509Data></ds:KeyInfo></md:KeyDescriptor>
Defensive patterns

Strategy: validation

Validate before calling

const hasKeyInfo = (xml: string): boolean => {
  const doc = new DOMParser().parseFromString(xml, 'application/xml');
  return ['md', 'ns0', 'ns2', 'dsig', 'ds', ''].some((p) =>
    doc.getElementsByTagName(p ? `${p}:KeyInfo` : 'KeyInfo').length > 0);
};

Type guard

const metadataHasSigningKeyInfo = (xml: string): boolean =>
  /<[^>]*KeyDescriptor[^>]*use=["']signing["'][\s\S]*?<[^>]*KeyInfo[\s\S]*?<\/[^>]*KeyDescriptor>/.test(xml);

Try / catch

const res = parseSAMLMetadataFromXMLFile(xml);
if (!res.success) {
  setFieldError('metadataFile', res.reason); // 'KeyInfo element is missing'
  return;
}

Prevention

When it happens

Trigger: KeyDescriptor exists but is self-closing or empty, or only carries an encryption role with no KeyInfo. KeyInfo is present but under a namespace prefix outside the md/ns0/ns2/dsig/ds allowlist, so getByPrefixAndKey returns undefined.

Common situations: IdP metadata where only an encryption KeyDescriptor is published and the signing one is stripped. Copy-paste of metadata truncates the KeyInfo subtree. Namespace prefix mismatch on the dsig portion.

Related errors


AI-assisted analysis of twentyhq/twenty@1f5dd2bbd2 (2026-08-12). Data as JSON: /api/errors/808f7a248d092c9c. Report an issue: GitHub.