From a31e7fb3eb91705fc8548f8468d1a402d50d3225 Mon Sep 17 00:00:00 2001 From: ehsan shariati Date: Thu, 18 Jun 2026 13:39:40 -0400 Subject: [PATCH] initipfscluster: self-heal a directory-shaped identity.json A plugin's file bind-mount (blox-ai) can make dockerd auto-create /uniondrive/ipfs-cluster/identity.json as a DIRECTORY when the real file is absent at container-create time. os.WriteFile then fails ("is a directory") and initipfscluster panics, leaving ipfs-cluster permanently wedged. Stat the path and os.RemoveAll a directory before writing so the real (deterministic) identity file is regenerated. Pairs with the fula-ota go-fula.sh guard and the readiness-check self-heal. Co-Authored-By: Claude Opus 4.8 --- modules/initipfscluster/main.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/modules/initipfscluster/main.go b/modules/initipfscluster/main.go index 91d61a6..21e9fa4 100644 --- a/modules/initipfscluster/main.go +++ b/modules/initipfscluster/main.go @@ -67,6 +67,18 @@ func main() { } } + // Docker bind-mount footgun guard: a plugin's *file* bind-mount (blox-ai) can + // create identity.json as a DIRECTORY when the real file is absent at + // container-create time. os.WriteFile below would then fail ("is a directory") + // and panic, leaving the cluster wedged. Remove a directory-shaped path so the + // real (deterministic) file can be written. + if fi, err := os.Stat(identityPath); err == nil && fi.IsDir() { + fmt.Println("identity.json is a directory (bind-mount artifact); removing before write") + if err := os.RemoveAll(identityPath); err != nil { + panic(fmt.Errorf("removing directory-shaped identity.json: %v", err)) + } + } + // Create directory and write identity.json if err := os.MkdirAll(clusterDir, 0755); err != nil { panic(fmt.Errorf("creating ipfs-cluster directory: %v", err))