halo-dev/halo · warning · Error

Provider resource path must be provider-root-relative: ${res

Error message

Provider resource path must be provider-root-relative: ${resourcePath}.

What it means

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.

Source

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

    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 ||
    normalizedSlashes.startsWith("/") ||
    normalizedSlashes.startsWith("//") ||
    /^[a-zA-Z][a-zA-Z\d+.-]*:/.test(normalizedSlashes) ||
    normalizedSlashes.includes("?") ||
    normalizedSlashes.includes("#")
  ) {
    throw new Error(
      `Provider resource path must be provider-root-relative: ${resourcePath}.`
    );
  }
  const normalized = path.posix.normalize(normalizedSlashes);
  if (normalized === ".." || normalized.startsWith("../")) {
    throw new Error(
      `Provider resource path escapes its root: ${resourcePath}.`
    );
  }
  return `./${normalized.replace(/^\.\//, "")}`;
}

function isRecord(value: unknown): value is Record<string, unknown> {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}

View on GitHub (pinned to d2f5165f9c)

Solutions

  1. Set "format": "esm" in ui-plugin.json.
  2. Rebuild the entry as an ES module (export/import syntax) so the value is truthful.
  3. If you cannot ship ESM, omit ui-plugin.json entirely to fall back to the legacy bundle path.

Example fix

// before
{
  "format": "module",
  "entry": "index.js"
}
// after
{
  "format": "esm",
  "entry": "index.js"
}
Defensive patterns

Strategy: validation

Validate before calling

if (!"esm".equals(manifest.path("format").textValue())) {
    throw new IllegalStateException("ui-plugin.json format must be 'esm'");
}

Prevention

When it happens

Trigger: A plugin's console/ui-plugin.json sets format to anything other than "esm".

Common situations: Porting a legacy IIFE/UMD bundle and forgetting to flip format; assuming "module" is accepted; case typo like "ESM".

Related errors


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