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

  1. Inspect the wrapped %v OS error for the exact cause
  2. Ensure StoreDir is writable by the server user (chown/chmod)
  3. Check for a regular file occupying the expected subdirectory path and remove it
  4. 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

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


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/e7fd20a26d2c21fe. Report an issue: GitHub.