nats-io/nats-server · error

failed to create temporary file: %w

Error message

failed to create temporary file: %w

What it means

Returned during atomic block overwrite (used by recompression) when creating the temporary file in the block directory fails. The rewrite strategy is write-to-temp-then-rename for atomicity; if the temp file cannot be created, the operation aborts without touching the original block.

Source

Thrown at server/filestore.go:8024

func (mb *msgBlock) atomicOverwriteFile(buf []byte, allowCompress bool) error {
	if mb.mfd != nil {
		mb.closeFDsLockedNoCheck()
		defer mb.enableForWriting(mb.fs.fip)
	}

	origFN := mb.mfn               // The original message block on disk.
	tmpFN := mb.mfn + blkTmpSuffix // The new block will be written here.

	// Rather than modifying the existing block on disk (which is a dangerous
	// operation if something goes wrong), create a new temporary file. We will
	// write out the new block here and then swap the files around afterwards
	// once everything else has succeeded correctly.
	mb.fs.dios.acquire()
	tmpFD, err := os.OpenFile(tmpFN, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, defaultFilePerms)
	mb.fs.dios.release()

	if err != nil {
		return fmt.Errorf("failed to create temporary file: %w", err)
	}

	errorCleanup := func(err error) error {
		_ = tmpFD.Close()
		_ = os.Remove(tmpFN)
		return err
	}

	alg := NoCompression
	if calg := mb.fs.fcfg.Compression; calg != NoCompression && allowCompress {
		alg = calg
		// The original buffer at this point is uncompressed, so we will now compress
		// it if needed. Note that if the selected algorithm is NoCompression, the
		// Compress function will just return the input buffer unmodified.
		originalSize := len(buf)
		if buf, err = alg.Compress(buf); err != nil {
			return errorCleanup(fmt.Errorf("failed to compress block: %w", err))
		}

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Check the wrapped cause: run df -h for ENOSPC or fix directory permissions for EACCES
  2. Ensure the jetstream datadir is on a writable, non-full volume
  3. Raise the fd limit if too many open files (ulimit -n / LimitNOFILE)
  4. Retry the recompression after storage is healthy; the original block is untouched

Example fix

# ENOSPC creating temp file during recompress
df -h /var/lib/nats
# free space or expand volume, then retry:
nats stream update ORDERS --compression=s2
Defensive patterns

Strategy: validation

Validate before calling

// Go: pre-flight writable-space check before triggering recompression
if free, err := diskFree(blockDir); err != nil || free < blockSize*2 {
    return fmt.Errorf("need 2x block size free in %s for atomic overwrite", blockDir)
}
if err := probeWritable(blockDir); err != nil {
    return fmt.Errorf("block dir not writable: %w", err)
}

Try / catch

if err != nil && strings.Contains(err.Error(), "failed to create temporary file") {
    switch {
    case strings.Contains(err.Error(), "no space left"):
        return freeSpaceThenRetry(cfg)
    case strings.Contains(err.Error(), "permission denied"):
        return fixDirPermsThenRetry(blockDir)
    default:
        return err
    }
}

Prevention

When it happens

Trigger: os.OpenFile(tmpFN, O_CREATE|O_TRUNC|O_WRONLY, ...) failing during recompression/overwrite: read-only filesystem, no write permission in the msgblk directory, disk full (ENOSPC), or too many open files.

Common situations: Datadir volume full during a compression migration; directory permissions changed by external tooling; running container with a read-only rootfs while jetstream data lives on it; EMFILE from many concurrent block operations.

Related errors


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