swc-project/swc · error · SyntaxError

The requested module

Error message

The requested module '{specifier}' does not provide an export named '{export_name}'

What it means

swc_xml_parser models parsing as three phases (Start, Main, End). This error means the input ended while the parser was still in the Start phase, i.e. no root element was ever opened. It is a recoverable parse error: the parser records it (with the EOF span) in its error list and then re-processes the EOF token in the End phase, so a Document is still returned by parse_file_as_document. The error appears in the `errors: &mut Vec<Error>` out-parameter, not as a Rust panic.

Solutions

  1. Inspect the reported span (it covers start_pos..last_pos of the file) and check what the input actually contains at that offset - usually it is empty or prolog-only.
  2. Ensure the document has exactly one root element, e.g. wrap loose content in a container element or emit `<root/>` for empty documents.
  3. If the input is produced by another process, verify it was flushed/closed completely before parsing (check file size, re-read the tail).
  4. Treat this error kind as fatal in your pipeline: after collecting `errors`, fail when ErrorKind::UnexpectedEofInStartPhase is present because the resulting Document has no root element child.

Example fix

// before: input.xml contains only a prolog
<?xml version="1.0"?>
<!-- no root -->

// after: add a single root element
<?xml version="1.0"?>
<root>
  <!-- content -->
</root>
Defensive patterns

Strategy: validation

Validate before calling

// After parsing, treat a missing root element as fatal:
use swc_xml_parser::error::ErrorKind;

let mut errors = Vec::new();
let doc = swc_xml_parser::parse_file_as_document(&fm, config, &mut errors)?;
if errors
    .iter()
    .any(|e| matches!(e.kind(), ErrorKind::UnexpectedEofInStartPhase))
{
    return Err("input has no root element (EOF in start phase)".into());
}
// cheap pre-check: does the input contain any '<' at all?
if !src.trim_start().starts_with('<') {
    return Err("not XML: no markup".into());
}

Try / catch

// Not a thrown error - it arrives via the `errors` out-parameter.
// Check the Vec and fail fast on structural kinds before consuming `doc`.
let structural = errors.iter().any(|e| matches!(
    e.kind(),
    ErrorKind::UnexpectedEofInStartPhase | ErrorKind::UnexpectedEofInMainPhase
));
if structural { return Err(ParseFailure::Malformed); }

Prevention

When it happens

Trigger: Calling swc_xml_parser::parse_file_as_document with a completely empty file, a file containing only whitespace/comments/processing instructions/doctype, or a file that was truncated before the first `<tag` was tokenized. Anything that never yields a Token::StartTag or Token::EmptyTag before Token::Eof.

Common situations: Templating systems that emit an empty skeleton XML file for new documents; pipelines where an upstream truncation or partial write produces an incomplete prolog; tests that feed fixture files consisting only of `<?xml ...?>` declarations; concatenating XML fragments where the root element was expected but never written.

Related errors


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

Appendix: source

Thrown at bindings/binding_nodejs_support_wasm/src/nodejs.rs:590

fn await_import(
    code: &str,
    specifier: &str,
    with: Option<&ObjectLit>,
    required_exports: &[String],
) -> String {
    let mut out = format!("{DYNAMIC_IMPORT_NAME}({}", json_string(specifier));
    if let Some(options) = import_options_to_dynamic_options(code, with) {
        out.push_str(", ");
        out.push_str(&options);
    }
    out.push(')');
    if !required_exports.is_empty() {
        out.push_str(".then((m) => { ");
        for export_name in required_exports {
            out.push_str("if (!(");
            out.push_str(&json_string(export_name));
            out.push_str(" in m)) throw new SyntaxError(");
            out.push_str(&json_string(&format!(
                "The requested module '{specifier}' does not provide an export named \
                 '{export_name}'"
            )));
            out.push_str("); ");
        }
        out.push_str("return m; })");
    }
    out
}

fn import_options_to_dynamic_options(code: &str, with: Option<&ObjectLit>) -> Option<String> {
    let attributes = slice_span(code, with?.span)?;
    Some(format!("{{ with: {attributes} }}"))
}

fn default_declaration_needs_parentheses(decl: &DefaultDecl) -> bool {
    matches!(decl, DefaultDecl::Class(class) if class.ident.is_none())

View on GitHub (pinned to 5176682b65)