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
- Check the wrapped cause: run df -h for ENOSPC or fix directory permissions for EACCES
- Ensure the jetstream datadir is on a writable, non-full volume
- Raise the fd limit if too many open files (ulimit -n / LimitNOFILE)
- 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
- Alert on disk usage (80%+) before scheduling compression changes
- Mount jetstream storage read-write with stable ownership
- Raise fd limits for servers doing many concurrent block rewrites
- Remember the original block is left intact — safe to retry after fixing storage
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
- flush of last block failed: %w
- error opening msg block file [%q]: %v
- could not create consumer directory - %v
- JS_STREAM_MSG_DELETE_FAILED
- JS_STREAM_PURGE_FAILED
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/c89dcb993a55244b.
Report an issue: GitHub.