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
- 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.
- Ensure the document has exactly one root element, e.g. wrap loose content in a container element or emit `<root/>` for empty documents.
- If the input is produced by another process, verify it was flushed/closed completely before parsing (check file size, re-read the tail).
- 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
- Generate XML through a serializer (it always emits a root element) instead of string templates.
- Validate generated documents in CI with xmllint --noout before shipping.
- When consuming streams, parse only after EOF so truncated inputs are never mistaken for complete documents.
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
- attempted to private field on non-instance
- Assignment to constant variable.
- attempted to get private field on non-instance
- attempted to reassign private method
- attempted to use private field on non-instance
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)