halo-dev/halo · error · Error
Host runtime snapshot packages must be an object.
Error message
Host runtime snapshot packages must be an object.
What it means
readPluginDescriptor computes a manifest path but Files.notExists(path) is true, so this PluginRuntimeException is thrown. It indicates the descriptor path was resolved yet does not exist on the filesystem at read time — a race or stale symlink.
Source
Thrown at ui/packages/ui-plugin-bundler-kit/src/runtime-snapshot.ts:54
const sharedPackageRootSet = new Set<string>(SHARED_PACKAGE_ROOTS);
export const HALO_HOST_RUNTIME_SNAPSHOTS = Object.freeze(
rawHaloHostRuntimeSnapshots.map(validateHaloHostRuntimeSnapshot)
);
export function validateHaloHostRuntimeSnapshot(
value: unknown
): HaloHostRuntimeSnapshot {
if (
!isRecord(value) ||
typeof value.haloVersion !== "string" ||
!parseStableVersion(value.haloVersion)
) {
throw new Error("Host runtime snapshot haloVersion must be stable semver.");
}
if (!isRecord(value.packages)) {
throw new Error("Host runtime snapshot packages must be an object.");
}
const snapshotPackages = value.packages;
const packageRoots = Object.keys(value.packages).sort();
const supportedRoots = [...SHARED_PACKAGE_ROOTS].sort();
if (
packageRoots.length !== supportedRoots.length ||
packageRoots.some((root, index) => root !== supportedRoots[index])
) {
throw new Error(
`Host runtime snapshot must expose exactly: ${SHARED_PACKAGE_ROOTS.join(", ")}.`
);
}
const packages = Object.fromEntries(
SHARED_PACKAGE_ROOTS.map((root) => [
root,
validateSnapshotEntry(root, snapshotPackages[root]),View on GitHub (pinned to d2f5165f9c)
Solutions
- Re-upload or re-place the plugin jar/directory and retry the install.
- Ensure the plugins directory is not being garbage-collected or moved concurrently.
- Verify the descriptor file is a real, readable file before calling install.
Defensive patterns
Strategy: validation
Validate before calling
Path manifest = getManifestPath(pluginPath, "plugin.yaml");
if (manifest == null || !Files.isReadable(manifest)) {
throw new IllegalStateException("plugin.yaml missing or unreadable: " + manifest);
} Try / catch
pluginService.install(path)
.onErrorResume(PluginRuntimeException.class,
e -> Mono.error(new BusinessException("Descriptor unreadable; re-upload: " + e.getMessage()))) Prevention
- Upload the full plugin file in one request; avoid concurrent cleanup.
- Ensure the plugins dir is stable and not symlinked to missing targets.
- Retry once on a clean copy before treating it as corrupt.
When it happens
Trigger: findPluginManifest resolves a descriptor path that is deleted/moved between resolution and the existence check, or points at a broken symlink.
Common situations: Concurrent cleanup of the plugins directory; partial upload where the file is removed mid-install; symlink to a missing target.
Related errors
- ESM provider manifest must contain format, entry, and option
- Host runtime snapshot haloVersion must be stable semver.
- Host runtime snapshot must expose exactly: ${SHARED_PACKAGE_
- Invalid target Halo version: ${targetHaloVersion}.
- Invalid attachment
AI-assisted analysis of halo-dev/halo@d2f5165f9c (2026-08-14).
Data as JSON: /api/errors/39aa538f9e09c70a.
Report an issue: GitHub.