swc-project/swc · error

`paths.{from}` should have only one wildcard

Error message

`paths.{from}` should have only one wildcard

What it means

When building the import resolver from tsconfig.json, each `paths` mapping key may contain at most one `*` wildcard: the resolver models the key as a literal prefix plus a single Pattern::Wildcard. A key containing two or more `*` characters panics during TsconfigResolver construction. This mirrors TypeScript's own rule that paths patterns allow one wildcard.

Source

Thrown at crates/swc_ecma_loader/src/resolvers/tsc.rs:77

            #[cfg(debug_assertions)]
            info!(
                base_url = tracing::field::display(base_url.display()),
                "jsc.paths"
            );
        }

        let mut paths: Vec<(Pattern, Vec<String>)> = paths
            .into_iter()
            .map(|(from, to)| {
                assert!(
                    !to.is_empty(),
                    "value of `paths.{from}` should not be an empty array",
                );

                let pos = from.as_bytes().iter().position(|&c| c == b'*');
                let pat = if from.contains('*') {
                    if from.as_bytes().iter().rposition(|&c| c == b'*') != pos {
                        panic!("`paths.{from}` should have only one wildcard")
                    }

                    Pattern::Wildcard {
                        prefix: from[..pos.unwrap()].to_string(),
                    }
                } else {
                    assert_eq!(
                        to.len(),
                        1,
                        "value of `paths.{from}` should be an array with one element because the \
                         src path does not contains * (wildcard)",
                    );

                    Pattern::Exact(from)
                };

                (pat, to)
            })

View on GitHub (pinned to 5176682b65)

Solutions

  1. Rewrite the offending paths key so it contains exactly one `*` (e.g. "utils/*" instead of "utils/*/*")
  2. Split one multi-wildcard entry into several entries, each anchored on a distinct literal prefix
  3. Run tsc against the same tsconfig as a sanity check; TypeScript rejects multi-wildcard paths keys too
  4. Add a startup assertion that scans paths keys for wildcard count before building the resolver

Example fix

// tsconfig.json - before
"paths": {
  "utils/*/*": ["src/utils/*/*"]
}

// tsconfig.json - after
"paths": {
  "utils/*": ["src/utils/*"],
  "utils/deep/*": ["src/utils/deep/*"]
}
Defensive patterns

Strategy: validation

Validate before calling

// JS: validate tsconfig paths before building the SWC resolver
function validatePaths(tsconfig) {
  for (const key of Object.keys(tsconfig.compilerOptions?.paths ?? {})) {
    const wildcards = [...key].filter(c => c === '*').length;
    if (wildcards > 1) {
      throw new Error(`paths key "${key}" has ${wildcards} wildcards; only one is allowed`);
    }
  }
}

Prevention

When it happens

Trigger: Constructing NodeImportResolver/TsconfigResolver with a tsconfig.json whose compilerOptions.paths contains a key like "utils/*/*"; the code finds the first `*` with position() and the last with rposition() and panics when they differ.

Common situations: Monorepo tsconfig files with nested wildcard patterns, configs hand-migrated from webpack/glob-style tooling, generating tsconfig programmatically with glob templates, invalid tsconfig passing a plain tsc check but never exercised for those paths.

Related errors


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