nats-io/nats-server · critical

failed to move temporary file into place: %w

Error message

failed to move temporary file into place: %w

What it means

Returned when os.Rename(tmpFN, origFN) fails while swapping the updated temporary block file into place after a successful write/sync/close. The new block data is fully written but could not atomically replace the original file, so the update fails with this wrapped error.

Source

Thrown at server/filestore.go:8075

	}

	// Write the new block data (which might be compressed or encrypted) to the
	// temporary file.
	if n, err := tmpFD.Write(buf); err != nil {
		return errorCleanup(fmt.Errorf("failed to write to temporary file: %w", err))
	} else if n != len(buf) {
		return errorCleanup(fmt.Errorf("short write to temporary file (%d != %d)", n, len(buf)))
	}
	if err := tmpFD.Sync(); err != nil {
		return errorCleanup(fmt.Errorf("failed to sync temporary file: %w", err))
	}
	if err := tmpFD.Close(); err != nil {
		return errorCleanup(fmt.Errorf("failed to close temporary file: %w", err))
	}

	// Now replace the original file with the newly updated temp file.
	if err := os.Rename(tmpFN, origFN); err != nil {
		return fmt.Errorf("failed to move temporary file into place: %w", err)
	}

	// Since the message block might be retained in memory, make sure the
	// compression algorithm is up-to-date, since this will be needed when
	// compacting or truncating.
	mb.cmp = alg

	// Also update rbytes
	mb.rbytes = uint64(len(buf))

	return nil
}

// Lock should be held.
func (mb *msgBlock) decompressIfNeeded(buf []byte) ([]byte, error) {
	var meta CompressionInfo
	if n, err := meta.UnmarshalMetadata(buf); err != nil {
		// There was a problem parsing the metadata header of the block.

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Ensure the entire JetStream store directory is on the same filesystem (no split symlinks/bind mounts).
  2. Verify write permission on the stream's data directory for the nats process user.
  3. Stop backup/AV agents from holding or removing files under the store directory mid-update.
  4. Retry the update once the directory state is fixed; the temp file may need manual removal if errorCleanup missed it.

Example fix

// before: split filesystems
StoreDir: /data/jetstream  # with symlink to /mnt/other/blockdir
// after: single filesystem
StoreDir: /data/jetstream  # entire tree on one volume
Defensive patterns

Strategy: validation

Validate before calling

// ensure store dir is one filesystem and writable before starting
info1, _ := os.Stat(storeDir)
dev := info1.Sys().(*syscall.Stat_t).Dev
if symlinkedAcrossDevices(storeDir) {
    return fmt.Errorf("store dir spans multiple filesystems")
}
if !writable(storeDir) {
    return fmt.Errorf("no write permission on %s", storeDir)
}

Try / catch

if err != nil && strings.Contains(err.Error(), "failed to move temporary file into place") {
    // check for EXDEV / permission issues; may need to remove leftover temp files
}

Prevention

When it happens

Trigger: os.Rename fails during the final commit step of a message block update — replacing the original block file with the temp file.

Common situations: Temp file and target on different filesystems (store dir partially relocated or symlinked), missing write permission on the directory (rename requires dir write), the original file removed/locked by backup agents, or cross-device link (EXDEV) errors in container volume setups.

Related errors


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