{"record":{"id":"d010094403405b4b","repo":"halo-dev/halo","slug":"esm-ui-provider-output-must-contain-exactly-one-en","errorCode":null,"errorMessage":"ESM UI provider output must contain exactly one entry JavaScript file.","messagePattern":"ESM UI provider output must contain exactly one entry JavaScript file\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"ui/packages/ui-plugin-bundler-kit/src/rsbuild-esm.ts","lineNumber":52,"sourceCode":"          test: /\\.[cm]?[jt]sx?$/,\n          enforce: \"post\",\n        },\n        async ({ code, resourcePath }) => {\n          await validator.validateSource(code, resourcePath);\n          return code;\n        }\n      );\n\n      api.processAssets(\n        { stage: \"summarize\" },\n        async ({ assets, compilation, sources }) => {\n          const entryFiles =\n            compilation.entrypoints.get(\"main\")?.getFiles() || [];\n          const entryScripts = entryFiles.filter((fileName) =>\n            fileName.endsWith(\".js\")\n          );\n          if (entryScripts.length !== 1) {\n            throw new Error(\n              \"ESM UI provider output must contain exactly one entry JavaScript file.\"\n            );\n          }\n          const entryFile = entryScripts[0];\n          const entry = assets[entryFile];\n          if (!entry) {\n            throw new Error(\n              `ESM UI provider output is missing its entry asset ${entryFile}.`\n            );\n          }\n          const entryCode = entry.source().toString();\n          await validator.validateSource(entryCode, entryFile);\n          if (\n            !/\\bexport\\s+default\\b/.test(entryCode) &&\n            !/\\bexport\\s*\\{[^}]*\\bdefault\\b[^}]*\\}/s.test(entryCode)\n          ) {\n            throw new Error(\n              \"ESM UI provider output must expose a default PluginModule export.\"","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/halo-dev/halo/blob/d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8/ui/packages/ui-plugin-bundler-kit/src/rsbuild-esm.ts#L34-L70","documentation":"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.","triggerScenarios":"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.","commonSituations":"Path typo; file not included in the jar build; case mismatch on case-sensitive filesystems; entry pointing outside the bundled console assets.","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."],"exampleFix":"// before — entry references a file not in the jar\n{\n  \"format\": \"esm\",\n  \"entry\": \"dist/main.js\"\n}\n// after — file actually shipped at console/index.js\n{\n  \"format\": \"esm\",\n  \"entry\": \"index.js\"\n}","handlingStrategy":"validation","validationCode":"// Confirm the entry/style file is packaged and readable inside console/.\nString p = normalizeObjectPath(manifest.path(\"entry\").asText());\nResource r = providerResource(candidate, p);\nif (r == null || !r.isReadable()) {\n    throw new IllegalStateException(\"Entry not packaged under console/: \" + p);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run `jar tf plugin.jar` to confirm console assets are present.","Match file names case-sensitively.","Rebuild after adding new assets."],"tags":["plugin","ui-bundle","esm","provider-manifest","packaging"],"backgroundTag":null,"analyzedSha":"d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8","analyzedAt":"2026-08-14T00:18:38.915Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}