parcel-bundler/parcel · error · ThrowableDiagnostic
Unexpected output file type ${ext} in target "${targetName}"
Error message
Unexpected output file type ${ext} in target "${targetName}" What it means
For a common named target (main/module/browser/types, defined in COMMON_TARGETS), Parcel validates that the configured `distEntry` (the output file path) has one of the expected extensions for that target type. If the extension is not in the allowed set, the build aborts with a disjunction list of allowed extensions.
Source
Thrown at packages/core/core/src/requests/TargetRequest.js:741
continue;
}
if (
distEntry != null &&
!COMMON_TARGETS[targetName].match.test(distEntry)
) {
let contents: string =
typeof pkgContents === 'string'
? pkgContents
: // $FlowFixMe
JSON.stringify(pkgContents, null, '\t');
// $FlowFixMe
let listFormat = new Intl.ListFormat('en-US', {type: 'disjunction'});
let extensions = listFormat.format(
COMMON_TARGETS[targetName].extensions,
);
let ext = path.extname(distEntry);
throw new ThrowableDiagnostic({
diagnostic: {
message: md`Unexpected output file type ${ext} in target "${targetName}"`,
origin: '@parcel/core',
codeFrames: [
{
language: 'json',
filePath: pkgFilePath ?? undefined,
code: contents,
codeHighlights: generateJSONCodeHighlights(contents, [
{
key: pointer,
type: 'value',
message: `File extension must be ${extensions}`,
},
]),
},
],
hints: [View on GitHub (pinned to 59484858a1)
Solutions
- Align the distEntry file extension with the target's expected extensions shown in the error (use one of the listed extensions).
- If you intentionally want a different format, configure `targets.<name>.outputFormat` and the matching extension explicitly.
- Remove the distEntry override and let Parcel infer the correct extension.
Example fix
// before (package.json)
{
"module": "dist/index.cjs"
}
// after
{
"module": "dist/index.mjs"
} Defensive patterns
Strategy: validation
Validate before calling
const COMMON_TARGETS = {
main: ['js','cjs'], module: ['mjs','js'], browser: ['js'], types: ['d.ts']
};
function assertDistEntryExt(targetName, distEntry) {
const ext = distEntry.split('.').pop();
const allowed = COMMON_TARGETS[targetName];
if (allowed && !allowed.includes(ext)) {
throw new Error(`Target ${targetName} expects .${allowed.join('|')}, got .${ext}`);
}
} Type guard
function isValidDistEntryForTarget(targetName, distEntry, allowed) {
const ext = distEntry.slice(distEntry.lastIndexOf('.') + 1);
return allowed.includes(ext);
} Try / catch
try { await parcel.run(); } catch (e) {
if (/Unexpected output file type/.test(e.message)) {
console.error('Fix the distEntry extension to match the target format.');
} else throw e;
} Prevention
- Pair `module` with .mjs, `main` with .js/.cjs, `types` with .d.ts.
- Let Parcel infer extensions by omitting distEntry where possible.
- Lint package.json with a schema describing target→extension rules.
When it happens
Trigger: Setting a distEntry for a COMMON_TARGET whose file extension differs from the target's expected set (e.g. pointing `module` at a `.cjs` file, or `main` at a `.mjs` while expecting commonjs).
Common situations: Mismatched field/extension pairs in package.json (e.g. `"main": "dist/index.mjs"` without esmodule config); leftover output paths after switching build format; copy-paste of build config between projects using different module formats.
Related errors
- Declared output format "${descriptor.outputFormat}" does not
- The "global" output format is not supported in the "${target
- Library targets are not supported in serve mode.
- Scope hoisting cannot be disabled for library targets.
- Invalid distPath for target "${targetName}"
AI-assisted analysis of parcel-bundler/parcel@59484858a1 (2026-08-13).
Data as JSON: /api/errors/12d28ee3c264e3a5.
Report an issue: GitHub.