nats-io/nats-server · critical

could not create storage directory - %v

Error message

could not create storage directory - %v

What it means

During file store setup, os.Stat shows the configured StoreDir does not exist, and the subsequent os.MkdirAll attempt failed (permissions, read-only filesystem, path conflicts). The underlying OS error is wrapped into this message. It indicates the server cannot provision its JetStream storage directory.

Source

Thrown at server/filestore.go:440

	}
	if fcfg.BlockSize > maxBlockSize {
		return nil, fmt.Errorf("filestore max block size is %s", friendlyBytes(maxBlockSize))
	}
	if fcfg.CacheExpire == 0 {
		fcfg.CacheExpire = defaultCacheBufferExpiration
	}
	if fcfg.SubjectStateExpire == 0 {
		fcfg.SubjectStateExpire = defaultFssExpiration
	}
	if fcfg.SyncInterval == 0 {
		fcfg.SyncInterval = defaultSyncInterval
	}
	dios := fcfg.srv.diskIOSemaphore()

	// Check the directory
	if stat, err := os.Stat(fcfg.StoreDir); os.IsNotExist(err) {
		if err := os.MkdirAll(fcfg.StoreDir, defaultDirPerms); err != nil {
			return nil, fmt.Errorf("could not create storage directory - %v", err)
		}
	} else if stat == nil || !stat.IsDir() {
		return nil, fmt.Errorf("storage directory is not a directory")
	}
	tmpfile, err := os.CreateTemp(fcfg.StoreDir, "_test_")
	if err != nil {
		return nil, fmt.Errorf("storage directory is not writable")
	}

	tmpfile.Close()
	dios.acquire()
	os.Remove(tmpfile.Name())
	dios.release()

	fs = &fileStore{
		fcfg:       fcfg,
		dios:       dios,
		psim:       stree.NewSubjectTree[psi](),

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Create the storage directory manually and grant the server user write permission (mkdir -p <dir>; chown)
  2. Fix StoreDir in the JetStream config to an existing writable path
  3. Check the wrapped %v OS error for the root cause (EACCES, EROFS, ENOTDIR)
  4. Verify the mount is writable if running in a container

Example fix

// before (server config)
store_dir: "/jetstream/data"
// after (ensure it exists and is writable first)
// $ sudo mkdir -p /jetstream/data && sudo chown nats:nats /jetstream/data
store_dir: "/jetstream/data"
Defensive patterns

Strategy: validation

Validate before calling

d := filepath.Join(storeDir, "..")
if fi, err := os.Stat(d); err != nil || !fi.IsDir() {
    return fmt.Errorf("parent of %s missing or not a directory", storeDir)
}
if err := os.MkdirAll(storeDir, 0o755); err != nil {
    return fmt.Errorf("pre-create store dir failed: %w", err)
}

Try / catch

if _, err := os.Stat(storeDir); err != nil {
    return fmt.Errorf("storage dir unusable: %w", err)
}

Prevention

When it happens

Trigger: os.Stat(StoreDir) returns fs.ErrNotExist and os.MkdirAll(StoreDir, defaultDirPerms) returns an error (server/filestore.go:440), e.g. parent directory not writable or StoreDir path invalid.

Common situations: JetBeam/StoreDir pointing to a path the server user cannot create (bad ownership, root-only parent); containers with read-only volumes; StoreDir containing a file component where a directory is needed elsewhere.

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/30ae144d9511efcf. Report an issue: GitHub.