{"record":{"id":"3f9c882bf84d1caa","repo":"nats-io/nats-server","slug":"could-not-create-storage-directory-v-3f9c88","errorCode":null,"errorMessage":"could not create storage directory - %v","messagePattern":"could not create storage directory - (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"server/jetstream.go","lineNumber":450,"sourceCode":"\ts.gcbMu.Lock()\n\tif s.gcbOutMax = s.getOpts().JetStreamMaxCatchup; s.gcbOutMax == 0 {\n\t\ts.gcbOutMax = defaultMaxTotalCatchupOutBytes\n\t}\n\ts.gcbMu.Unlock()\n\n\tatomic.StoreInt64(&js.memMax, cfg.MaxMemory)\n\tatomic.StoreInt64(&js.storeMax, cfg.MaxStore)\n\n\t// TODO: Not currently reloadable.\n\tatomic.StoreInt64(&js.queueLimit, s.getOpts().JetStreamRequestQueueLimit)\n\tatomic.StoreInt64(&js.infoQueueLimit, s.getOpts().JetStreamInfoQueueLimit)\n\n\ts.js.Store(js)\n\n\t// FIXME(dlc) - Allow memory only operation?\n\tif stat, err := os.Stat(cfg.StoreDir); os.IsNotExist(err) {\n\t\tif err := os.MkdirAll(cfg.StoreDir, defaultDirPerms); err != nil {\n\t\t\treturn fmt.Errorf(\"could not create storage directory - %v\", err)\n\t\t}\n\t} else {\n\t\t// Make sure its a directory and that we can write to it.\n\t\tif stat == nil || !stat.IsDir() {\n\t\t\treturn fmt.Errorf(\"storage directory is not a directory\")\n\t\t}\n\t\ttmpfile, err := os.CreateTemp(cfg.StoreDir, \"_test_\")\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"storage directory is not writable\")\n\t\t}\n\t\ttmpfile.Close()\n\t\tos.Remove(tmpfile.Name())\n\t}\n\n\tif err := s.initJetStreamEncryption(); err != nil {\n\t\treturn err\n\t}\n","sourceCodeStart":432,"sourceCodeEnd":468,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/jetstream.go#L432-L468","documentation":"JetStream enablement: the configured StoreDir does not exist and os.MkdirAll failed (commonly permissions or an invalid path), so the storage directory for streams could not be created.","triggerScenarios":"First-time JetStream startup where cfg.StoreDir (jetstream { store_dir: ... }) points to a nonexistent directory and mkdir -p style creation fails — e.g. parent dirs missing and not creatable, insufficient permissions, or read-only mount.","commonSituations":"store_dir under a path the nats-server user can't write; typo'd path on a non-existent mountpoint; container with read-only filesystem; SELinux/AppArmor blocking directory creation.","solutions":["Create the directory manually with correct ownership: mkdir -p <store_dir> && chown nats:nats <store_dir>","Check the filesystem is writable and mounted (df/mount) before starting the server","Fix store_dir in config to a valid writable path","Check SELinux/AppArmor/deny logs if creation is blocked by policy"],"exampleFix":"// before\njetstream { store_dir: \"/data/js\" } // /data missing or read-only\n// after\n// mkdir -p /data/js && chown nats:nats /data/js\njetstream { store_dir: \"/data/js\" }","handlingStrategy":"validation","validationCode":"// Before starting the server:\nif fi, err := os.Stat(storeDir); err != nil {\n    if err := os.MkdirAll(storeDir, 0750); err != nil { return err }\n} else if !fi.IsDir() {\n    return fmt.Errorf(\"%s is not a directory\", storeDir)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pre-create store_dir in deployment tooling with correct ownership","Verify the path's mount exists and is writable before service start","Run the server under a dedicated user with write access to the store path","In containers, mount a volume at the store path instead of using container-local FS"],"tags":["jetstream","storage","filesystem","permissions"],"backgroundTag":"storage-directory-unwritable","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}