From 4e8cbe88f17b723d9cc4f57d073c31744d6fab98 Mon Sep 17 00:00:00 2001 From: Gonzalo Aune <219565+gonzaloaune@users.noreply.github.com> Date: Wed, 2 Sep 2026 13:29:53 +0000 Subject: [PATCH] [Jamie] Fix Host Storage MALFORMED: allow null docker_root_dir/filesystem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem The admin Host Storage panel returns `{"outcome":"failed","reasonCode":"MALFORMED"}` for swarm boxes where the storage collector cannot resolve the Docker root filesystem (e.g. instance `i-0622bd22c313f7227`, also seen on `i-0d7b27a21ef9d3863`). ## Root cause Confirmed as a Hive-side schema/contract drift, not a box problem: - The sphinx-swarm `GetHostStorage` command runs successfully on the box and returns a valid `HostStorage` payload. Box log: `GetHostStorage source=none host_visible=false root_free_bytes=None neo4j_bytes=Some(...) errors=2` - In the Rust struct (`src/host_stats.rs`), `docker_root_dir` and `docker_root_filesystem` are `Option`. When the docker root cannot be resolved they serialize to `null`. - In Hive's `hostStorageSchema` (`src/services/swarm/host-storage.ts`), both fields are plain required `cappedString` (`z.string().transform(capString)`) with no `.nullable()`. A `null` value fails `safeParse` → `parseHostStorage` returns `MALFORMED`. ## Fix Make `docker_root_dir` and `docker_root_filesystem` nullable in `hostStorageSchema` to match the swarm's `Option` contract. This is the same treatment already applied to the `neo4j` field (`z.nullable(...)`). --- src/services/swarm/host-storage.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/services/swarm/host-storage.ts b/src/services/swarm/host-storage.ts index 3d015877b2..23e996fe80 100644 --- a/src/services/swarm/host-storage.ts +++ b/src/services/swarm/host-storage.ts @@ -68,8 +68,8 @@ export const hostStorageSchema = z.object({ collected_at: z.number().int(), cached: z.boolean(), filesystems: z.array(contractFilesystemSchema).transform(capArray), - docker_root_dir: cappedString, - docker_root_filesystem: cappedString, + docker_root_dir: z.nullable(cappedString), + docker_root_filesystem: z.nullable(cappedString), volumes: z.array(contractVolumeSchema).transform(capArray), neo4j: z.nullable(contractNeo4jSchema), errors: z.array(contractErrorSchema).transform(capArray), @@ -268,8 +268,8 @@ export function parseHostStorage(response: SwarmCmdResponse): HostStorageReading collectedAt: contract.collected_at, cached: contract.cached, filesystems, - dockerRootDir: contract.docker_root_dir, - dockerRootFilesystem: contract.docker_root_filesystem, + dockerRootDir: contract.docker_root_dir ?? "", + dockerRootFilesystem: contract.docker_root_filesystem ?? "", governingFilesystem, volumes, neo4j,