halo-dev/halo · warning · Error

Provider resource path escapes its root: ${resourcePath}.

Error message

Provider resource path escapes its root: ${resourcePath}.

What it means

validateManifestResource requires the entry (and style) values in ui-plugin.json to be JSON strings. A non-textual node (number, object, array, boolean) throws this IllegalArgumentException, caught upstream and reported as ClassifiedProvider.invalid.

Source

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

}

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. Make entry and style plain string paths in ui-plugin.json.
  2. Point them at the actual file relative to the console/ provider root.
  3. Validate the manifest shape with a JSON schema in the build.

Example fix

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

Strategy: validation

Validate before calling

JsonNode entry = manifest.path("entry");
if (!entry.isTextual()) {
    throw new IllegalStateException("ui-plugin.json entry must be a string path");
}

Type guard

static boolean isStringPath(JsonNode n) { return n != null && n.isTextual() && StringUtils.hasText(n.asText()); }

Prevention

When it happens

Trigger: ui-plugin.json's entry or style is a non-string JSON value, e.g. "entry": 42 or "entry": {"src":"x.js"}.

Common situations: Author wraps the path in an object; build tool writes a numeric token; misconfigured manifest generator.

Related errors


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