halo-dev/halo · error · Error
Explicit ESM output requires a simple stable spec.requires t
Error message
Explicit ESM output requires a simple stable spec.requires target or targetHaloVersion.
What it means
Thrown by selectProviderFormat when the caller explicitly requests ESM output (format: 'esm') but neither spec.requires nor targetHaloVersion can be parsed by parseSimpleStableTarget/parse into a simple stable MAJOR.MINOR.PATCH. ESM output needs a concrete Halo target to select the right host runtime snapshot, so without a derivable target the kit cannot safely emit ESM.
Source
Thrown at ui/packages/ui-plugin-bundler-kit/src/utils/halo-plugin.ts:108
reason: "automatic",
targetHaloVersion: derivedTarget,
warnings: [],
};
}
return {
format: "esm",
reason: "automatic",
targetHaloVersion: derivedTarget,
warnings: [],
};
}
const explicitTarget = options.targetHaloVersion
? parse(options.targetHaloVersion)
: undefined;
const target = derivedTarget || explicitTarget?.version;
if (!target) {
throw new Error(
"Explicit ESM output requires a simple stable spec.requires target or targetHaloVersion."
);
}
const warnings: string[] = [];
if (!derivedTarget) {
warnings.push(
`Explicit ESM output uses target Halo ${target}, but spec.requires ${JSON.stringify(options.requires)} does not prove a minimum Halo version of ${ESM_PROVIDER_MIN_HALO_VERSION} or newer. Update spec.requires so older Halo releases do not install this ESM-only artifact.`
);
} else if (!gte(derivedTarget, ESM_PROVIDER_MIN_HALO_VERSION)) {
warnings.push(
`Explicit ESM output targets Halo ${derivedTarget}, which predates ESM UI provider support in Halo ${ESM_PROVIDER_MIN_HALO_VERSION}.`
);
}
return {
format: "esm",
reason: "explicit",
targetHaloVersion: target,View on GitHub (pinned to d2f5165f9c)
Solutions
- Set spec.requires in plugin.yaml to a simple stable target like '>=2.26.0'.
- Pass targetHaloVersion: '2.26.0' (no 'v' prefix, no prerelease) to selectProviderFormat.
- Drop the explicit esm override and let format default to 'auto', which falls back to IIFE when no target is derivable.
Example fix
// before
selectProviderFormat({ format: "esm", requires: "^2.0.0" });
// after
selectProviderFormat({ format: "esm", requires: ">=2.26.0" }); Defensive patterns
Strategy: validation
Validate before calling
import { parse } from "semver";
function assertEsmTarget(opts: { requires?: string; targetHaloVersion?: string }) {
const m = opts.requires?.trim().match(/^(?:>=)?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/);
const target = m ? `${m[1]}.${m[2]}.${m[3]}` : (opts.targetHaloVersion && parse(opts.targetHaloVersion)?.version);
if (!target) {
throw new Error("Provide a simple stable spec.requires (>=MAJOR.MINOR.PATCH) or targetHaloVersion for ESM output.");
}
} Type guard
import { parse } from "semver";
function isSimpleStableTarget(value: unknown): value is string {
return typeof value === "string" &&
/^(?:>=)?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.test(value.trim());
} Prevention
- Always set spec.requires to a simple '>=X.Y.Z' in plugin.yaml when opting into ESM.
- Pass targetHaloVersion without a 'v' prefix and without prerelease tags.
- Prefer format: 'auto' so the kit falls back to IIFE instead of throwing.
When it happens
Trigger: Called with { format: 'esm' } (or a config resolving to explicit esm) while options.requires is undefined/complex (e.g. '>=2.20 <2.26', '~2.25', '^2.0') AND options.targetHaloVersion is omitted or non-semver. parseSimpleStableTarget only accepts an optional '>=' prefix followed by exactly MAJOR.MINOR.PATCH.
Common situations: Setting format:'esm' in vite config but leaving plugin.yaml spec.requires as a range or empty; passing a targetHaloVersion with a 'v' prefix or prerelease; CI that forces esm without setting a target.
Related errors
- ${root} resolved to invalid version ${resolved.version} at $
- ${root} snapshot version must be stable semver.
- ${root} snapshot exports must be unique identifiers.
- ${root} snapshot runtime descriptor is invalid.
- Unsupported shared dependency subpath ${specifier} imported
AI-assisted analysis of halo-dev/halo@d2f5165f9c (2026-08-14).
Data as JSON: /api/errors/1e3ab1c83c1cdc1c.
Report an issue: GitHub.