nats-io/nats-server · error

failed to load block from disk: %w

Error message

failed to load block from disk: %w

What it means

Wraps any error from mb.loadBlock(nil) that occurs while truncating the last message block: if the block is compressed and/or encrypted, it must be fully loaded into memory first. This error means the block file could not be read/validated from disk (IO error, checksum failure, or underlying corruption like 'sanity check failed').

Source

Thrown at server/filestore.go:6878

				if rl > mb.bytes {
					rl = mb.bytes
				}
				mb.bytes -= rl
				mb.rbytes -= rl
				// For return accounting.
				purged++
				bytes += uint64(rl)
			}
		}
	}

	// If the block is compressed/encrypted then we have to load it into memory
	// and decompress/decrypt it, truncate it and then write it back out.
	// Otherwise, truncate the file itself and close the descriptor.
	if mb.cmp != NoCompression || mb.bek != nil {
		buf, err := mb.loadBlock(nil)
		if err != nil {
			return 0, 0, fmt.Errorf("failed to load block from disk: %w", err)
		}
		if err = mb.encryptOrDecryptIfNeeded(buf); err != nil {
			return 0, 0, err
		}
		if buf, err = mb.decompressIfNeeded(buf); err != nil {
			return 0, 0, fmt.Errorf("failed to decompress block: %w", err)
		}
		buf = buf[:eof]
		copy(mb.lchk[0:], buf[len(buf)-checksumSize:])
		// We did decompress but don't recompress the truncated buffer here since we're the last block
		// and would otherwise have compressed data and allow to write uncompressed data in the same block.
		if err = mb.atomicOverwriteFile(buf, false); err != nil {
			return 0, 0, err
		}
	} else if mb.mfd != nil {
		if err = mb.mfd.Truncate(eof); err != nil {
			return 0, 0, err
		}

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Inspect the wrapped cause (read error vs checksum vs sanity check) with debug logging
  2. Remove/reset the affected stream files so JetStream recreates them (accepting data loss for that stream)
  3. Restore the store directory from a consistent offline backup
  4. Run filesystem/disk health checks and replace failing hardware
Defensive patterns

Strategy: try-catch

Validate before calling

// Before trim/compact operations, verify store volume readability and space
if info, err := os.Stat(storeDir); err != nil || !info.IsDir() {
    return fmt.Errorf("store dir unreadable: %v", err)
}

Try / catch

// Go: inspect the wrapped cause of 'failed to load block from disk'
if _, _, err := truncateLastBlock(mb, eof); err != nil {
    var ioErr *os.PathError
    if errors.As(err, &ioErr) {
        // OS-level read failure: check disk/filesystem
    } else if strings.Contains(err.Error(), "sanity check") {
        // corrupt block: restore backup or reset stream
    }
    return err
}

Prevention

When it happens

Trigger: Trimming/compacting the last block of a stream (truncateMsgs path) when the block has compression (mb.cmp != NoCompression) or encryption (mb.bek != nil) and loadBlock fails — unreadable file, bad checksum, corrupt record layout.

Common situations: Corrupt or truncated block files after crashes, failing disks, restored backups missing chunks, or read errors at the OS level (EIO).

Related errors


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