{"record":{"id":"48d1c8d7bf2bbd4f","repo":"halo-dev/halo","slug":"esm-provider-manifest-must-contain-format-entry","errorCode":null,"errorMessage":"ESM provider manifest must contain format, entry, and optional style only with format \"esm\".","messagePattern":"ESM provider manifest must contain format, entry, and optional style only with format \"esm\"\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ui/packages/ui-plugin-bundler-kit/src/provider-manifest.ts","lineNumber":24,"sourceCode":"  format: \"esm\";\n  entry: string;\n  style?: string;\n}\n\nexport function validateEsmProviderManifest(\n  value: unknown\n): EsmProviderManifest {\n  if (!isRecord(value)) {\n    throw new Error(\"ESM provider manifest must be an object.\");\n  }\n  const keys = Object.keys(value).sort();\n  if (\n    !keys.includes(\"entry\") ||\n    !keys.includes(\"format\") ||\n    keys.some((key) => ![\"entry\", \"format\", \"style\"].includes(key)) ||\n    value.format !== \"esm\"\n  ) {\n    throw new Error(\n      'ESM provider manifest must contain format, entry, and optional style only with format \"esm\".'\n    );\n  }\n  if (typeof value.entry !== \"string\") {\n    throw new Error(\"ESM provider manifest entry is required.\");\n  }\n  const manifest: EsmProviderManifest = {\n    format: \"esm\",\n    entry: normalizeProviderResourcePath(value.entry),\n  };\n  if (\"style\" in value) {\n    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}","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/halo-dev/halo/blob/d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8/ui/packages/ui-plugin-bundler-kit/src/provider-manifest.ts#L6-L42","documentation":"PluginUtils.generateFileName throws ServerWebInputException (HTTP 400) when plugin.getSpec().getVersion() is null or blank. The method builds the stored jar name as \"<metadata.name>-<version>.jar\" and is invoked during install/upgrade copy (PluginServiceImpl.copyToPluginHome) and by PluginReconciler, so a blank version aborts installation and can block reconciliation.","triggerScenarios":"Installing/upgrading or reconciling a plugin whose plugin.yaml omits spec.version, sets it to an empty string, or places it under the wrong YAML key so it deserializes to null.","commonSituations":"plugin.yaml missing the version field; wrong indentation putting version outside spec; version set to \"\"; templating that stripped the value during build.","solutions":["Add a valid semantic version to spec.version in plugin.yaml (e.g. version: 1.0.0).","Verify YAML indentation so version sits directly under spec.","Validate the descriptor schema in the plugin build pipeline before publishing the jar."],"exampleFix":"// before\nspec:\n  displayName: My Plugin\n  # version missing\n// after\nspec:\n  displayName: My Plugin\n  version: 1.0.0","handlingStrategy":"validation","validationCode":"// Reject a blank version before attempting install/reconcile.\nString v = plugin.getSpec().getVersion();\nif (!StringUtils.hasText(v)) {\n    throw new IllegalStateException(\"plugin.yaml spec.version must be a non-blank semver\");\n}","typeGuard":"// Java predicate narrowing a Plugin to 'has a usable version'\nstatic boolean hasValidVersion(Plugin p) {\n    return p != null && p.getSpec() != null\n        && StringUtils.hasText(p.getSpec().getVersion());\n}","tryCatchPattern":"Mono.fromCallable(() -> PluginUtils.generateFileName(plugin))\n    .onErrorResume(ServerWebInputException.class,\n        e -> Mono.error(new BusinessException(\"Set spec.version in plugin.yaml\")))","preventionTips":["Always set spec.version in plugin.yaml scaffolds.","Add a schema/required-field check to the plugin build.","Treat a blank version as a build failure, not a runtime surprise."],"tags":["plugin","versioning","install","validation","manifest"],"backgroundTag":null,"analyzedSha":"d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8","analyzedAt":"2026-08-14T00:18:38.915Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}