halo-dev/halo · warning · Error

ESM provider manifest entry is required.

Error message

ESM provider manifest entry is required.

What it means

Inside UiPluginBundleServiceImpl.readManifest the parsed ui-plugin.json root must be a JSON object; if it is an array, string, number, or scalar this IllegalArgumentException is thrown. It is caught one frame up and converted into ClassifiedProvider.invalid(candidate, message), so the provider is marked invalid rather than crashing the bundle build — the plugin's ESM UI bundle will not be served.

Source

Thrown at ui/packages/ui-plugin-bundler-kit/src/provider-manifest.ts:29

export function validateEsmProviderManifest(
  value: unknown
): EsmProviderManifest {
  if (!isRecord(value)) {
    throw new Error("ESM provider manifest must be an object.");
  }
  const keys = Object.keys(value).sort();
  if (
    !keys.includes("entry") ||
    !keys.includes("format") ||
    keys.some((key) => !["entry", "format", "style"].includes(key)) ||
    value.format !== "esm"
  ) {
    throw new Error(
      'ESM provider manifest must contain format, entry, and optional style only with format "esm".'
    );
  }
  if (typeof value.entry !== "string") {
    throw new Error("ESM provider manifest entry is required.");
  }
  const manifest: EsmProviderManifest = {
    format: "esm",
    entry: normalizeProviderResourcePath(value.entry),
  };
  if ("style" in value) {
    if (typeof value.style !== "string") {
      throw new Error("ESM provider manifest style must be a string.");
    }
    manifest.style = normalizeProviderResourcePath(value.style);
  }
  return manifest;
}

export function normalizeProviderResourcePath(resourcePath: string) {
  const normalizedSlashes = resourcePath.replaceAll("\\", "/");
  if (
    !normalizedSlashes ||

View on GitHub (pinned to d2f5165f9c)

Solutions

  1. Make ui-plugin.json a single JSON object with format, entry, and optional style fields.
  2. Re-run the plugin scaffold/manifest generator to regenerate a well-formed ui-plugin.json.
  3. Lint the JSON in CI before packaging the plugin jar.

Example fix

// before — ui-plugin.json
["module.js"]
// after
{
  "format": "esm",
  "entry": "module.js"
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate ui-plugin.json shape before packaging the jar.
JsonNode n = JSON_MAPPER.readTree(uiPluginJsonFile);
if (!n.isObject()) {
    throw new IllegalStateException("ui-plugin.json must be a JSON object");
}

Type guard

static boolean isManifestObject(JsonNode n) { return n != null && n.isObject(); }

Prevention

When it happens

Trigger: A plugin ships a console/ui-plugin.json whose top-level JSON value is not an object (e.g. a bare array of providers or a string), read when the UI bundle service classifies the provider.

Common situations: Author hand-edits ui-plugin.json into an array; build tool emits a JSON array instead of an object; truncation/corruption leaving a scalar.

Related errors


AI-assisted analysis of halo-dev/halo@d2f5165f9c (2026-08-14). Data as JSON: /api/errors/b14128c9a4dee4a5. Report an issue: GitHub.