rolldown/rolldown · error
ModuleType token should be followed by a string, but got
Error message
ModuleType token should be followed by a string, but got {other:?} What it means
The `moduleType` operator in a filter expression must be followed immediately by a string literal naming the module type. The parser (`rec`, invoked from public `parse`) bails with this error when any other token follows the `moduleType` token, because `FilterExpr::ModuleType` only carries a string.
Solutions
- Quote the module type value, e.g. `moduleType('js')`.
- Verify the expression is complete and not truncated after the `moduleType` token.
- Use only string module type values matching known module types (js, jsx, ts, css, json, asset, ...).
Example fix
// before
parse("moduleType(/css/)")
// after
parse("moduleType('css')") Defensive patterns
Strategy: validation
Validate before calling
// before serializing moduleType filter
function assertModuleType(v) {
if (typeof v !== 'string') {
throw new TypeError(`moduleType expects a string, got: ${typeof v}`);
}
} Type guard
function isStringModuleType(v) {
return typeof v === 'string' && v.length > 0;
} Try / catch
try {
parse(expr);
} catch (e) {
if (String(e).includes('ModuleType token should be followed by a string')) {
// correct the expression: moduleType('...')
}
throw e;
} Prevention
- Quote the module type: moduleType('css'), never moduleType(/css/).
- Check the expression is not truncated right after moduleType.
- Reuse shared constants for module type names to avoid typos.
When it happens
Trigger: Parsing an expression like `moduleType(/regex/)` or `moduleType(true)`, or an expression that ends right after `moduleType` so a leftover/truncated token is popped instead of a string.
Common situations: Typos in hand-written serialized filter expressions used by builtin plugin filters; passing a regex instead of a string for the module type; string truncation when the expression is embedded in JSON config and quotes are mis-escaped.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- value of `Query` should be a string, regex, or boolean, but…
- Boolean token should not appear standalone
- Exclude token should not appear inside an expression
- filter expression is empty
- filter expression should start with Include or Exclude, but…
AI-assisted analysis of rolldown/rolldown@91b44b9d7b (2026-09-07).
Data as JSON: /api/errors/47cfb95bd31fc5c4.
Report an issue: GitHub.
Appendix: source
Thrown at crates/rolldown_utils/src/filter_expression.rs:301
let key = match pop(tokens)? {
Token::String(key) => key,
other => anyhow::bail!("key of `Query` should be a string, but got {other:?}"),
};
let value = match pop(tokens)? {
Token::String(v) => QueryValue::String(v),
Token::Regex(v) => QueryValue::Regex(v),
Token::Boolean(v) => QueryValue::Boolean(v),
other => anyhow::bail!(
"value of `Query` should be a string, regex, or boolean, but got {other:?}"
),
};
Ok(FilterExpr::Query(key, value))
}
Token::ModuleType => {
let string = match pop(tokens)? {
Token::String(s) => s,
other => {
anyhow::bail!("ModuleType token should be followed by a string, but got {other:?}")
}
};
Ok(FilterExpr::ModuleType(string))
}
Token::And(arg_count) => {
let mut args = Vec::with_capacity(arg_count as usize);
for _ in 0..arg_count {
args.push(rec(tokens)?);
}
Ok(FilterExpr::And(args))
}
Token::Or(arg_count) => {
let mut args = Vec::with_capacity(arg_count as usize);
for _ in 0..arg_count {
args.push(rec(tokens)?);
}
Ok(FilterExpr::Or(args))
}View on GitHub (pinned to 91b44b9d7b)