{"record":{"id":"39aa538f9e09c70a","repo":"halo-dev/halo","slug":"host-runtime-snapshot-packages-must-be-an-object","errorCode":null,"errorMessage":"Host runtime snapshot packages must be an object.","messagePattern":"Host runtime snapshot packages must be an object\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ui/packages/ui-plugin-bundler-kit/src/runtime-snapshot.ts","lineNumber":54,"sourceCode":"\nconst sharedPackageRootSet = new Set<string>(SHARED_PACKAGE_ROOTS);\n\nexport const HALO_HOST_RUNTIME_SNAPSHOTS = Object.freeze(\n  rawHaloHostRuntimeSnapshots.map(validateHaloHostRuntimeSnapshot)\n);\n\nexport function validateHaloHostRuntimeSnapshot(\n  value: unknown\n): HaloHostRuntimeSnapshot {\n  if (\n    !isRecord(value) ||\n    typeof value.haloVersion !== \"string\" ||\n    !parseStableVersion(value.haloVersion)\n  ) {\n    throw new Error(\"Host runtime snapshot haloVersion must be stable semver.\");\n  }\n  if (!isRecord(value.packages)) {\n    throw new Error(\"Host runtime snapshot packages must be an object.\");\n  }\n  const snapshotPackages = value.packages;\n\n  const packageRoots = Object.keys(value.packages).sort();\n  const supportedRoots = [...SHARED_PACKAGE_ROOTS].sort();\n  if (\n    packageRoots.length !== supportedRoots.length ||\n    packageRoots.some((root, index) => root !== supportedRoots[index])\n  ) {\n    throw new Error(\n      `Host runtime snapshot must expose exactly: ${SHARED_PACKAGE_ROOTS.join(\", \")}.`\n    );\n  }\n\n  const packages = Object.fromEntries(\n    SHARED_PACKAGE_ROOTS.map((root) => [\n      root,\n      validateSnapshotEntry(root, snapshotPackages[root]),","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/halo-dev/halo/blob/d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8/ui/packages/ui-plugin-bundler-kit/src/runtime-snapshot.ts#L36-L72","documentation":"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.","triggerScenarios":"findPluginManifest resolves a descriptor path that is deleted/moved between resolution and the existence check, or points at a broken symlink.","commonSituations":"Concurrent cleanup of the plugins directory; partial upload where the file is removed mid-install; symlink to a missing target.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"Path manifest = getManifestPath(pluginPath, \"plugin.yaml\");\nif (manifest == null || !Files.isReadable(manifest)) {\n    throw new IllegalStateException(\"plugin.yaml missing or unreadable: \" + manifest);\n}","typeGuard":null,"tryCatchPattern":"pluginService.install(path)\n    .onErrorResume(PluginRuntimeException.class,\n        e -> Mono.error(new BusinessException(\"Descriptor unreadable; re-upload: \" + e.getMessage())))","preventionTips":["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."],"tags":["plugin","manifest","install","filesystem","race"],"backgroundTag":null,"analyzedSha":"d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8","analyzedAt":"2026-08-14T00:18:38.915Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}