{"record":{"id":"62167843b1d69af2","repo":"floci-io/floci","slug":"persistent-storage-path-root-toabsolutepath","errorCode":null,"errorMessage":"Persistent storage path '\" + root.toAbsolutePath() + \"' is not writable, but non-memory storage is enabled (\" + services + \"). Fix the volume mount permissions (it may be read-only or root-owned), or point FLOCI_STORAGE_PERSISTENT_PATH at a writable directory.","messagePattern":"Persistent storage path '\" \\+ root\\.toAbsolutePath\\(\\) \\+ \"' is not writable, but non-memory storage is enabled \\(\" \\+ services \\+ \"\\)\\. Fix the volume mount permissions \\(it may be read-only or root-owned\\), or point FLOCI_STORAGE_PERSISTENT_PATH at a writable directory\\.","errorType":"panic","errorClass":"IllegalStateException","httpStatus":null,"severity":"critical","filePath":"src/main/java/io/github/hectorvent/floci/core/storage/PersistentPathValidator.java","lineNumber":58,"sourceCode":"            return;\n        }\n\n        Path root = Path.of(config.storage().persistentPath());\n        try {\n            probeWritable(root);\n            Path s3Root = root.resolve(\"s3\");\n            boolean s3Persistent = persistent.stream().anyMatch(d -> \"s3\".equals(d.storageKey()));\n            if (s3Persistent && Files.isDirectory(s3Root)) {\n                probeWritable(s3Root);\n            }\n        } catch (IOException | SecurityException e) {\n            String services = persistent.stream()\n                    .map(d -> d.storageKey() + \"=\" + d.storageMode())\n                    .distinct()\n                    .limit(8)\n                    .reduce((a, b) -> a + \", \" + b)\n                    .orElse(\"\");\n            throw new IllegalStateException(\n                    \"Persistent storage path '\" + root.toAbsolutePath()\n                            + \"' is not writable, but non-memory storage is enabled (\" + services\n                            + \"). Fix the volume mount permissions (it may be read-only or root-owned),\"\n                            + \" or point FLOCI_STORAGE_PERSISTENT_PATH at a writable directory.\", e);\n        }\n    }\n\n    static void probeWritable(Path dir) throws IOException {\n        Files.createDirectories(dir);\n        Path probe = Files.createTempFile(dir, \".floci-write-probe\", null);\n        try {\n            Files.deleteIfExists(probe);\n        } catch (IOException e) {\n            // The write itself succeeded, so the path is writable; a failed cleanup\n            // must not abort boot as a false \"not writable\".\n            probe.toFile().deleteOnExit();\n        }\n    }","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/floci-io/floci/blob/62ff490619e7bd3554597c28c704081b4c15add5/src/main/java/io/github/hectorvent/floci/core/storage/PersistentPathValidator.java#L40-L76","documentation":"Thrown by PersistentPathValidator.validateAtBoot at startup when a write probe under the persistent storage root (including the s3 subdirectory when S3 is persistent) fails with IOException or SecurityException while any non-memory storage mode is enabled. The message lists the affected services and modes, and tells you to fix volume permissions or relocate FLOCI_STORAGE_PERSISTENT_PATH. The emulator refuses to boot rather than silently losing persistence.","triggerScenarios":"Running floci in Docker with the persistence directory on a read-only or root-owned volume mount while floci.storage.mode (or per-service modes) is persistent/hybrid/wal; probeWritable creates a temp file '.floci-write-probe' and fails.","commonSituations":"Docker volume owned by root while the container runs as a non-root user; read-only bind mounts; SELinux denying writes to the mount; NFS/EFS mounts with restrictive perms; Kubernetes hostPath volumes without fsGroup.","solutions":["Make the persistence directory writable by the emulator user: chown -R <uid>:<gid> <host-path> or chmod, then restart","Or point FLOCI_STORAGE_PERSISTENT_PATH / floci.storage.persistent-path at a writable directory","For Kubernetes, set the pod securityContext fsGroup / runAsUser to match the volume ownership","If persistence is not needed, switch storage mode to memory"],"exampleFix":"# before\ndocker run -v /data/floci:/var/lib/floci my/floci  # /data/floci owned by root\n\n# after\nsudo chown -R 1000:1000 /data/floci\ndocker run -u 1000 -v /data/floci:/var/lib/floci my/floci","handlingStrategy":"validation","validationCode":"// pre-flight the persistence dir with the same probe floci uses\nstatic void probeWritable(Path dir) throws IOException {\n    Files.createDirectories(dir);\n    Path probe = Files.createTempFile(dir, \".floci-write-probe\", null);\n    Files.deleteIfExists(probe);\n}","typeGuard":null,"tryCatchPattern":"try {\n    app.run(args);\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"not writable\")) { fixVolumeOwnership(); } // then restart; no in-app workaround\n}","preventionTips":["Chown persistence volumes to the container user before first boot","In Kubernetes, set fsGroup to match the volume's group","Add a compose init step or entrypoint chmod/chown for named volumes","Smoke-test writability of mounted paths in CI before starting floci"],"tags":["storage","persistence","docker","permissions","startup"],"backgroundTag":null,"analyzedSha":"62ff490619e7bd3554597c28c704081b4c15add5","analyzedAt":"2026-08-14T14:25:23.764Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}