parcel-bundler/parcel · error · ThrowableDiagnostic
Missing distDir for target "${name}"
Error message
Missing distDir for target "${name}" What it means
Thrown by TargetRequest.resolve() when targets are passed as an object map (not an array) and a target descriptor is missing the required distDir property. distDir specifies the output directory for that target and is mandatory for object-form targets. A code frame highlights the offending target in the serialized options.
Source
Thrown at packages/core/core/src/requests/TargetRequest.js:263
.filter(Boolean);
} else {
// Otherwise, it's an object map of target descriptors (similar to those
// in package.json). Adapt them to native targets.
targets = Object.entries(optionTargets)
.map(([name, _descriptor]) => {
let {distDir, ...descriptor} = parseDescriptor(
name,
_descriptor,
null,
JSON.stringify({targets: optionTargets}, null, '\t'),
);
if (distDir == null) {
let optionTargetsString = JSON.stringify(
optionTargets,
null,
'\t',
);
throw new ThrowableDiagnostic({
diagnostic: {
message: md`Missing distDir for target "${name}"`,
origin: '@parcel/core',
codeFrames: [
{
code: optionTargetsString,
codeHighlights: generateJSONCodeHighlights(
optionTargetsString || '',
[
{
key: `/${name}`,
type: 'value',
},
],
),
},
],
},View on GitHub (pinned to 59484858a1)
Solutions
- Add a distDir property to the target descriptor in the options object.
- If you want the default output directory, set distDir to 'dist' explicitly.
- Verify every target in the object map has distDir — the code frame shows which one is missing.
- Consider using package.json targets instead, where distDir can be inferred from the target name.
Example fix
// before
const bundler = new Parcel({
entries: 'src/index.html',
targets: {
app: {
context: 'browser',
outputFormat: 'esmodule'
// distDir missing
}
}
});
// after
const bundler = new Parcel({
entries: 'src/index.html',
targets: {
app: {
distDir: 'dist',
context: 'browser',
outputFormat: 'esmodule'
}
}
}); Defensive patterns
Strategy: validation
Validate before calling
function validateObjectTargetsHaveDistDir(targets) {
if (targets == null || Array.isArray(targets)) return;
for (const [name, descriptor] of Object.entries(targets)) {
if (descriptor.distDir == null) {
throw new Error(`Target "${name}" is missing required "distDir" property.`);
}
}
} Type guard
function hasAllDistDirs(targets) {
if (targets == null || Array.isArray(targets)) return true;
return Object.entries(targets).every(([, d]) => d != null && typeof d.distDir === 'string' && d.distDir.length > 0);
} Prevention
- When passing targets as an object, always include distDir for each entry.
- Prefer package.json targets where distDir can be inferred from the target name.
- Validate the targets object shape before constructing the Parcel instance.
When it happens
Trigger: In the Object.entries(optionTargets).map() branch, parseDescriptor extracts distDir from the descriptor. If distDir == null (absent or explicitly null), the error fires with a JSON code frame showing the target's value in the option targets string.
Common situations: Passing targets as an object programmatically and forgetting distDir; copy-pasting a target descriptor from package.json (which can infer distDir) into the API (which cannot); assuming distDir defaults to 'dist' — it does not for object-form targets.
Related errors
- Targets option is an empty array
- Could not find target with name "${target}"
- More than one target is not supported in serve mode
- Library targets are not supported in serve mode.
- Unexpected output file type ${ext} in target "${targetName}"
AI-assisted analysis of parcel-bundler/parcel@59484858a1 (2026-08-13).
Data as JSON: /api/errors/1965018340069fa0.
Report an issue: GitHub.