swc-project/swc · error · anyhow::Error

failed to parse namespace of context element

Error message

failed to parse namespace of context element

What it means

The HTML Node binding converts the JS-side context element (used for fragment parsing) into a swc_html_ast::Element via create_namespace, which accepts exactly six well-known namespace URIs (XHTML, MathML, SVG, XLINK, XML, XMLNS), compared after to_lowercase(). Any other namespace string on the context element or one of its attributes fails here, before parsing starts. The check is exact string matching, so a trailing slash or typo is enough.

Source

Thrown at bindings/binding_html_node/src/lib.rs:234

        Ok(output)
    }
}

enum DocumentOrDocumentFragment {
    Document(Document),
    DocumentFragment(DocumentFragment),
}

fn create_namespace(namespace: &str) -> anyhow::Result<Namespace> {
    match &*namespace.to_lowercase() {
        "http://www.w3.org/1999/xhtml" => Ok(Namespace::HTML),
        "http://www.w3.org/1998/math/mathml" => Ok(Namespace::MATHML),
        "http://www.w3.org/2000/svg" => Ok(Namespace::SVG),
        "http://www.w3.org/1999/xlink" => Ok(Namespace::XLINK),
        "http://www.w3.org/xml/1998/namespace" => Ok(Namespace::XML),
        "http://www.w3.org/2000/xmlns/" => Ok(Namespace::XMLNS),
        _ => {
            bail!("failed to parse namespace of context element")
        }
    }
}

fn create_element(context_element: Element) -> anyhow::Result<swc_html_ast::Element> {
    let mut attributes = Vec::with_capacity(context_element.attributes.len());

    for attribute in context_element.attributes.into_iter() {
        let namespace = match attribute.namespace {
            Some(namespace) => Some(create_namespace(&namespace)?),
            _ => None,
        };

        attributes.push(swc_html_ast::Attribute {
            span: DUMMY_SP,
            namespace,
            prefix: attribute.prefix.map(|value| value.into()),
            name: attribute.name.into(),

View on GitHub (pinned to 5176682b65)

Solutions

  1. Use exactly one of the six URIs: 'http://www.w3.org/1999/xhtml', 'http://www.w3.org/1998/math/mathml', 'http://www.w3.org/2000/svg', 'http://www.w3.org/1999/xlink', 'http://www.w3.org/xml/1998/namespace', 'http://www.w3.org/2000/xmlns/' (note: only xmlns ends with a slash)
  2. Omit the namespace field entirely when the element or attribute has no namespace
  3. Map or strip custom namespaces in your own code before passing the context element to the binding

Example fix

// before
const res = parseSync(src, {
  contextElement: {
    tagName: 'svg',
    namespace: 'http://www.w3.org/2000/svg/', // trailing slash -> bail
  },
});

// after
const res = parseSync(src, {
  contextElement: {
    tagName: 'svg',
    namespace: 'http://www.w3.org/2000/svg',
  },
});
Defensive patterns

Strategy: validation

Validate before calling

const KNOWN_NAMESPACES = new Set([
  'http://www.w3.org/1999/xhtml',
  'http://www.w3.org/1998/math/mathml',
  'http://www.w3.org/2000/svg',
  'http://www.w3.org/1999/xlink',
  'http://www.w3.org/xml/1998/namespace',
  'http://www.w3.org/2000/xmlns/',
]);
function normalizeNamespace(ns) {
  if (ns == null) return undefined;
  const lower = ns.toLowerCase();
  if (!KNOWN_NAMESPACES.has(lower)) {
    throw new RangeError(`unsupported namespace: ${ns}`);
  }
  return lower;
}
contextElement.namespace = normalizeNamespace(contextElement.namespace);

Type guard

const isKnownNamespace = (ns: string): boolean =>
  new Set([
    'http://www.w3.org/1999/xhtml',
    'http://www.w3.org/1998/math/mathml',
    'http://www.w3.org/2000/svg',
    'http://www.w3.org/1999/xlink',
    'http://www.w3.org/xml/1998/namespace',
    'http://www.w3.org/2000/xmlns/',
  ]).has(ns.toLowerCase());

Try / catch

try {
  const res = parseSync(src, { contextElement });
} catch (e) {
  if (String(e?.message).includes('namespace of context element')) {
    return parseSync(src, { contextElement: stripNamespaces(contextElement) });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling the HTML parse API in fragment mode with options.contextElement whose namespace (or an attribute's namespace) is not one of the six URIs, e.g. 'http://www.w3.org/2000/svg/' (trailing slash), 'https://www.w3.org/2000/svg' (https), or a custom namespace like 'http://example.com/ns'.

Common situations: Copy-pasted namespace URIs with typos or trailing slashes; XML-first pipelines emitting custom xmlns declarations into the context element; TypeScript users assuming any string is fine because the binding types namespace as plain string; case differences are tolerated (lowercased) but scheme/slash differences are not.

Understand the failure class

Related errors


AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17). Data as JSON: /api/errors/8a39307c7333c398. Report an issue: GitHub.