halo-dev/halo · warning · Error
ESM UI provider output must contain exactly one entry JavaSc
Error message
ESM UI provider output must contain exactly one entry JavaScript file.
What it means
After path normalization, validateManifestResource looks up the entry/style resource inside the provider root (the console/ bundle location) and checks isReadable(); if it is missing or unreadable this IllegalArgumentException is thrown and converted to ClassifiedProvider.invalid. The literal path from the manifest is included in the message.
Source
Thrown at ui/packages/ui-plugin-bundler-kit/src/rsbuild-esm.ts:52
test: /\.[cm]?[jt]sx?$/,
enforce: "post",
},
async ({ code, resourcePath }) => {
await validator.validateSource(code, resourcePath);
return code;
}
);
api.processAssets(
{ stage: "summarize" },
async ({ assets, compilation, sources }) => {
const entryFiles =
compilation.entrypoints.get("main")?.getFiles() || [];
const entryScripts = entryFiles.filter((fileName) =>
fileName.endsWith(".js")
);
if (entryScripts.length !== 1) {
throw new Error(
"ESM UI provider output must contain exactly one entry JavaScript file."
);
}
const entryFile = entryScripts[0];
const entry = assets[entryFile];
if (!entry) {
throw new Error(
`ESM UI provider output is missing its entry asset ${entryFile}.`
);
}
const entryCode = entry.source().toString();
await validator.validateSource(entryCode, entryFile);
if (
!/\bexport\s+default\b/.test(entryCode) &&
!/\bexport\s*\{[^}]*\bdefault\b[^}]*\}/s.test(entryCode)
) {
throw new Error(
"ESM UI provider output must expose a default PluginModule export."View on GitHub (pinned to d2f5165f9c)
Solutions
- Confirm the entry/style file is packaged under the plugin's console/ directory.
- Match the path spelling and case exactly to the file on disk.
- Rebuild the jar and verify with `jar tf` that the console asset is present.
Example fix
// before — entry references a file not in the jar
{
"format": "esm",
"entry": "dist/main.js"
}
// after — file actually shipped at console/index.js
{
"format": "esm",
"entry": "index.js"
} Defensive patterns
Strategy: validation
Validate before calling
// Confirm the entry/style file is packaged and readable inside console/.
String p = normalizeObjectPath(manifest.path("entry").asText());
Resource r = providerResource(candidate, p);
if (r == null || !r.isReadable()) {
throw new IllegalStateException("Entry not packaged under console/: " + p);
} Prevention
- Run `jar tf plugin.jar` to confirm console assets are present.
- Match file names case-sensitively.
- Rebuild after adding new assets.
When it happens
Trigger: ui-plugin.json's entry or style points at a file that is not packaged inside the plugin's console/ directory, or the file exists but is unreadable.
Common situations: Path typo; file not included in the jar build; case mismatch on case-sensitive filesystems; entry pointing outside the bundled console assets.
Related errors
- ESM provider manifest entry is required.
- ESM provider manifest style must be a string.
- Provider resource path must be provider-root-relative: ${res
- Provider resource path escapes its root: ${resourcePath}.
- ESM UI provider output is missing its entry asset ${entryFil
AI-assisted analysis of halo-dev/halo@d2f5165f9c (2026-08-14).
Data as JSON: /api/errors/d010094403405b4b.
Report an issue: GitHub.