nats-io/nats-server · critical
could not create message storage directory - %v
Error message
could not create message storage directory - %v
What it means
After the base StoreDir checks pass, the file store creates the per-stream messages subdirectory (filepath.Join(StoreDir, msgDir)); os.MkdirAll failure is wrapped with the OS error. This happens later in newFileStoreWithCreatedAndMode, typically due to permissions or a filesystem error inside an existing directory.
Source
Thrown at server/filestore.go:488
// Register with access time service.
ats.Register()
// If we error before completion make sure to cleanup.
defer func() {
if err != nil {
ats.Unregister()
}
}()
// Set flush in place to AsyncFlush which by default is false.
fs.fip = !fcfg.AsyncFlush
// Check if this is a new setup.
mdir := filepath.Join(fcfg.StoreDir, msgDir)
odir := filepath.Join(fcfg.StoreDir, consumerDir)
if err := os.MkdirAll(mdir, defaultDirPerms); err != nil {
return nil, fmt.Errorf("could not create message storage directory - %v", err)
}
if err := os.MkdirAll(odir, defaultDirPerms); err != nil {
return nil, fmt.Errorf("could not create consumer storage directory - %v", err)
}
// Create highway hash for message blocks. Use sha256 of directory as key.
key := sha256.Sum256([]byte(cfg.Name))
fs.hh, err = highwayhash.NewDigest64(key[:])
if err != nil {
return nil, fmt.Errorf("could not create hash: %v", err)
}
keyFile := filepath.Join(fs.fcfg.StoreDir, JetStreamMetaFileKey)
_, err = os.Stat(keyFile)
// Either the file should exist (err=nil), or it shouldn't. Any other error is reported.
if err != nil && !os.IsNotExist(err) {
return nil, err
}View on GitHub (pinned to 3a66a489d2)
Solutions
- Inspect the wrapped %v OS error for the exact cause
- Ensure StoreDir is writable by the server user (chown/chmod)
- Check for a regular file occupying the expected subdirectory path and remove it
- Check disk space and security policies (SELinux/AppArmor) on the volume
Example fix
// before // $ ls /data/jetstream/my-stream/ => msgs (a file) // after // $ rm /data/jetstream/my-stream/msgs // server restarts and creates msgs/ directory
Defensive patterns
Strategy: try-catch
Validate before calling
if err := os.MkdirAll(filepath.Join(storeDir, "msgs"), 0o755); err != nil {
return fmt.Errorf("msgs dir pre-check failed: %w", err)
} Try / catch
if err := startStream(); err != nil {
if strings.Contains(err.Error(), "could not create message storage directory") {
// inspect wrapped OS error, fix perms/space, then restart
}
} Prevention
- Check disk space and permissions on the store dir before creating streams
- Watch for files colliding with the msgs directory name
- Review SELinux/AppArmor denials if perms look correct
When it happens
Trigger: os.MkdirAll(mdir, defaultDirPerms) fails when creating the 'msgs' directory inside StoreDir (server/filestore.go:488).
Common situations: StoreDir writable but on a full filesystem; SELinux/AppArmor blocking nested creation; a file named like the msg subdirectory already exists; racing cleanup removed StoreDir mid-setup.
Understand the failure class
Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.
Related errors
- could not create storage directory - %v
- storage directory is not writable
- could not create consumer storage directory - %v
- storage directory is not a directory
- failed to write to temporary file: %w
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/e7fd20a26d2c21fe.
Report an issue: GitHub.