oxc-project/oxc · warning · OxcDiagnostic
Expected a literal string or immutable template literal
Error message
Expected a literal string or immutable template literal
What it means
Diagnostic from the oxlint rule import/no-dynamic-require (restriction category). It fires when the module argument of `require(...)` is not statically known — not a string literal and not a no-substitution template literal. Runtime-computed paths defeat static analysis: bundlers cannot trace them, code navigation breaks, and lint rules that need resolved modules (like no-cycle or no-named-as-default) silently lose visibility. With the `esmodule: true` option, `import(...)` expressions are checked the same way.
Source
Thrown at crates/oxc_linter/src/rules/import/no_dynamic_require.rs:15
use oxc_ast::{AstKind, ast::Expression};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{GetSpan, Span};
use schemars::JsonSchema;
use serde::Deserialize;
use crate::{
AstNode,
context::LintContext,
rule::{DefaultRuleConfig, Rule},
};
fn no_dnyamic_require_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Expected a literal string or immutable template literal")
.with_help("Replace the argument with a literal string or immutable template literal")
.with_label(span)
}
#[derive(Debug, Default, Clone, JsonSchema, Deserialize)]
#[serde(rename_all = "camelCase", default, deny_unknown_fields)]
pub struct NoDynamicRequire {
/// When `true`, also check `import()` expressions for dynamic module specifiers.
esmodule: bool,
}
declare_oxc_lint!(
/// ### What it does
///
/// Forbids imports that use an expression for the module argument. This includes
/// dynamically resolved paths in `require` or `import` statements.
///
/// ### Why is this bad?View on GitHub (pinned to e1e7af627c)
Solutions
- Replace the computed path with a literal string, or a template literal without substitutions
- Replace open-ended dynamic loading with an explicit static require map: `const modules = { a: () => require("./a"), b: () => require("./b") }` — keys stay analyzable
- For genuinely dynamic loading (plugins, routes), scope the rule off for that file/directory and use bundler-native mechanisms (import.meta.glob, webpack context) deliberately
- If import() with expressions is accepted in your codebase, do not enable `esmodule: true`
Example fix
// before
require(`../locales/${locale}.json`);
// after
const localeFiles = {
en: () => require("../locales/en.json"),
de: () => require("../locales/de.json"),
};
localeFiles[locale](); Defensive patterns
Strategy: validation
Validate before calling
// fail on computed require paths before review:
// rg -n "require\\s*\\(\\s*[^'\"`]" src --type js
// .oxlintrc.json: { "rules": { "import/no-dynamic-require": ["warn", { "esmodule": true }] } } Prevention
- Prefer a static require map with literal keys for finite module sets
- Use bundler-native dynamic loading (import.meta.glob, webpack require.context) and scope this rule off those files
- Only enable esmodule:true when your bundler truly cannot trace import(expr)
When it happens
Trigger: `require(name)`, `require("../" + name)`, `require(\`../${name}\`)`, `require(name())`; also `import(name)` / `import(\`../${name}\`)` when configured with `{ "esmodule": true }`. Only the first argument of require is checked, so `require("./foo", "bar" + "okay")` passes. Emitted from no_dnyamic_require_diagnostic at crates/oxc_linter/src/rules/import/no_dynamic_require.rs:15 via is_static_value.
Common situations: Plugin loaders, i18n/locale loading, and config discovery code that builds paths at runtime; migrations that moved to bundlers (webpack/rollup/vite) where dynamic require breaks or warns; teams enabling esmodule checking after adopting dynamic import().
Related errors
- Could not find the reuseWorker option in ${path}
- Do not assign to imported bindings
- Backreference '{back_reference}' will be ignored. It referen
- Expected '{curr_kind}' syntax before '{prev_kind}' syntax.
- Imports should be sorted alphabetically.
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/a5df8ec264137b71.
Report an issue: GitHub.