{"record":{"id":"5a8e7ffd0a6ce35a","repo":"halo-dev/halo","slug":"provider-resource-path-must-be-provider-root-relat","errorCode":null,"errorMessage":"Provider resource path must be provider-root-relative: ${resourcePath}.","messagePattern":"Provider resource path must be provider-root-relative: (.+?)\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"ui/packages/ui-plugin-bundler-kit/src/provider-manifest.ts","lineNumber":54,"sourceCode":"    if (typeof value.style !== \"string\") {\n      throw new Error(\"ESM provider manifest style must be a string.\");\n    }\n    manifest.style = normalizeProviderResourcePath(value.style);\n  }\n  return manifest;\n}\n\nexport function normalizeProviderResourcePath(resourcePath: string) {\n  const normalizedSlashes = resourcePath.replaceAll(\"\\\\\", \"/\");\n  if (\n    !normalizedSlashes ||\n    normalizedSlashes.startsWith(\"/\") ||\n    normalizedSlashes.startsWith(\"//\") ||\n    /^[a-zA-Z][a-zA-Z\\d+.-]*:/.test(normalizedSlashes) ||\n    normalizedSlashes.includes(\"?\") ||\n    normalizedSlashes.includes(\"#\")\n  ) {\n    throw new Error(\n      `Provider resource path must be provider-root-relative: ${resourcePath}.`\n    );\n  }\n  const normalized = path.posix.normalize(normalizedSlashes);\n  if (normalized === \"..\" || normalized.startsWith(\"../\")) {\n    throw new Error(\n      `Provider resource path escapes its root: ${resourcePath}.`\n    );\n  }\n  return `./${normalized.replace(/^\\.\\//, \"\")}`;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n  return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","sourceCodeStart":36,"sourceCodeEnd":70,"githubUrl":"https://github.com/halo-dev/halo/blob/d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8/ui/packages/ui-plugin-bundler-kit/src/provider-manifest.ts#L36-L70","documentation":"readManifest enforces that ui-plugin.json's format field equals the literal \"esm\". Any other value (e.g. \"iife\", \"module\", \"umd\") throws this IllegalArgumentException, caught and turned into ClassifiedProvider.invalid. Only ESM providers are supported.","triggerScenarios":"A plugin's console/ui-plugin.json sets format to anything other than \"esm\".","commonSituations":"Porting a legacy IIFE/UMD bundle and forgetting to flip format; assuming \"module\" is accepted; case typo like \"ESM\".","solutions":["Set \"format\": \"esm\" in ui-plugin.json.","Rebuild the entry as an ES module (export/import syntax) so the value is truthful.","If you cannot ship ESM, omit ui-plugin.json entirely to fall back to the legacy bundle path."],"exampleFix":"// before\n{\n  \"format\": \"module\",\n  \"entry\": \"index.js\"\n}\n// after\n{\n  \"format\": \"esm\",\n  \"entry\": \"index.js\"\n}","handlingStrategy":"validation","validationCode":"if (!\"esm\".equals(manifest.path(\"format\").textValue())) {\n    throw new IllegalStateException(\"ui-plugin.json format must be 'esm'\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Build entry bundles as ES modules and set format to 'esm'.","If you cannot ship ESM, omit ui-plugin.json to use the legacy bundle path.","Pin the manifest generator that always writes 'esm'."],"tags":["plugin","ui-bundle","esm","provider-manifest","validation"],"backgroundTag":null,"analyzedSha":"d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8","analyzedAt":"2026-08-14T00:18:38.915Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}