nats-io/nats-server · critical

storage directory is not writable

Error message

storage directory is not writable

What it means

EnableJetStream performs a write probe (os.CreateTemp) inside an existing StoreDir to confirm writability; if creating a temp file fails, the directory exists but the server process cannot write to it.

Source

Thrown at server/jetstream.go:459

	// TODO: Not currently reloadable.
	atomic.StoreInt64(&js.queueLimit, s.getOpts().JetStreamRequestQueueLimit)
	atomic.StoreInt64(&js.infoQueueLimit, s.getOpts().JetStreamInfoQueueLimit)

	s.js.Store(js)

	// FIXME(dlc) - Allow memory only operation?
	if stat, err := os.Stat(cfg.StoreDir); os.IsNotExist(err) {
		if err := os.MkdirAll(cfg.StoreDir, defaultDirPerms); err != nil {
			return fmt.Errorf("could not create storage directory - %v", err)
		}
	} else {
		// Make sure its a directory and that we can write to it.
		if stat == nil || !stat.IsDir() {
			return fmt.Errorf("storage directory is not a directory")
		}
		tmpfile, err := os.CreateTemp(cfg.StoreDir, "_test_")
		if err != nil {
			return fmt.Errorf("storage directory is not writable")
		}
		tmpfile.Close()
		os.Remove(tmpfile.Name())
	}

	if err := s.initJetStreamEncryption(); err != nil {
		return err
	}

	// JetStream is an internal service so we need to make sure we have a system account.
	// This system account will export the JetStream service endpoints.
	if s.SystemAccount() == nil {
		s.SetDefaultSystemAccount()
	}

	opts := s.getOpts()
	if !opts.DisableJetStreamBanner {
		s.Noticef("    _ ___ _____ ___ _____ ___ ___   _   __  __")

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. chown/chmod the store dir so the server's user can write (e.g. chown -R nats:nats <store_dir>)
  2. Check disk space (df -h) and read-only mounts (mount | grep ro)
  3. Fix container/runtime mounts so the store path is writable (PVC/emptyDir)
  4. Test writability manually: sudo -u nats touch <store_dir>/_test_

Example fix

// before
// drwxr-xr-x root root /var/lib/nats/js, server runs as nats
// after
// chown nats:nats /var/lib/nats/js && chmod 750 /var/lib/nats/js
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight write probe as the nats-server user:
sudo -u nats test -w "$STORE_DIR" || echo "store dir not writable by nats"
sudo -u nats touch "$STORE_DIR/_preflight_" && rm "$STORE_DIR/_preflight_"

Prevention

When it happens

Trigger: StoreDir is a valid directory but the nats-server process user lacks write permission, the disk is full, the filesystem is mounted read-only, or immutable/ACL attributes block file creation.

Common situations: Running server as non-root user against a root-owned dir; disk-full conditions (df shows 100%); read-only remount after disk errors; Kubernetes readOnlyRootFilesystem without an emptyDir/PVC for the store path.

Related errors


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