Ubuntu · Boot recovery

Fix Ubuntu kernel panic: VFS unable to mount root fs on unknown-block(0,0)

Published Sep 19, 2026 · Ubuntu dual-boot / NVMe · ~8 min read

From GRUB to a mounted Ubuntu root filesystem on NVMe
Healthy path: GRUB → kernel + initrd → NVMe drivers → root mount.

If Ubuntu dies right after GRUB with VFS: Unable to mount root fs on unknown-block(0,0), the kernel usually started — and then lost the plot before it could open the root disk. On modern NVMe installs, that almost always points at a missing or incomplete initrd, not a dead drive.

What the panic means

Ubuntu’s kernel prints that message when the Virtual File System layer cannot attach a root block device. unknown-block(0,0) is the smoking gun: major/minor 0,0 means “we never got a real device.”

So this is usually not:

It is usually:

Diagram showing the initrd gap between Ubuntu kernel load and root filesystem mount
The initrd is the bridge between “kernel is alive” and “root filesystem is mountable.”

Why initrd matters on Ubuntu + NVMe

On many Ubuntu desktops and laptops, the root filesystem lives on NVMe (/dev/nvme0n1pN). NVMe drivers are commonly loaded from the initial RAM disk. If GRUB starts the kernel without a usable initrd, the kernel has no bridge to the disk — and you get unknown-block(0,0).

Dual-boot clue: If Windows still boots from the same GRUB menu, the disk and firmware path are probably fine. Ubuntu’s early boot payload is the broken piece.

Classic symptoms

Recover right now

Four-step checklist to fix Ubuntu boot failures
Use Advanced options first. Permanent cleanup comes after you have a shell.

1) Boot a known-good kernel from GRUB

At the GRUB menu, open Advanced options for Ubuntu and pick an older kernel. If that boots, you already proved the disk and Ubuntu root are alive.

2) Inspect what GRUB is actually loading

Highlight Ubuntu → press e. You want both lines:

linux   /boot/vmlinuz-VERSION root=... ro quiet splash
initrd  /boot/initrd.img-VERSION

If initrd is missing, adding the matching file can be a one-boot workaround — but only if that file exists on disk.

Make the fix permanent

Once you are inside a working Ubuntu session:

uname -r
ls -1 /boot/vmlinuz* /boot/initrd.img*
ls /lib/modules
df -h /boot /

# Rebuild initrd for a kernel that still has modules
sudo update-initramfs -c -k $(uname -r)
# or a specific version that exists under /lib/modules:
# sudo update-initramfs -c -k 7.0.0-28-generic

sudo update-grub

If a kernel is only a leftover vmlinuz with no modules and apt cannot reinstall it, remove the orphans instead of chasing a ghost package:

sudo rm -f /boot/vmlinuz-BROKEN /boot/initrd.img-BROKEN \
  /boot/System.map-BROKEN /boot/config-BROKEN
sudo update-grub

GRUB traps that cause repeat panics

A hidden zero-second timeout with GRUB_DEFAULT=0 will keep auto-selecting whatever is first — even if that entry has a kernel and no initrd.

sudo sed -i 's/^GRUB_TIMEOUT_STYLE=.*/GRUB_TIMEOUT_STYLE=menu/; s/^GRUB_TIMEOUT=.*/GRUB_TIMEOUT=5/' /etc/default/grub
sudo update-grub

After reboot you should see the menu long enough to choose a known-good Ubuntu kernel while you finish cleanup.

Case study hardware (ThinkPad T490s)

Laptop on a desk running a Linux desktop environment
This failure mode is an Ubuntu early-boot problem. The laptop brand is secondary.

The walkthrough above is for Ubuntu on any NVMe dual-boot box. For completeness, the machine that triggered this write-up was a Lenovo ThinkPad T490s (typical PSREF family specs):

ModelLenovo ThinkPad T490s (14" ultraportable)
CPU8th-gen Intel Core i5/i7 U-series (e.g. i5-8265U / i7-8565U class), 4 cores / 8 threads
GraphicsIntel UHD Graphics 620
MemoryUp to 32 GB soldered DDR4-2400
StorageM.2 SSD up to 1 TB (PCIe NVMe or SATA options)
Display14" FHD IPS options (250–400 nits) or WQHD 2560×1440 IPS up to 500 nits
Battery / sizeUp to ~57 Wh; about 16 mm thin, starting ~1.27 kg
Observed layoutGPT dual-boot; Ubuntu root on /dev/nvme0n1p3; Windows still chainloaded from GRUB

On that install, a newer Ubuntu kernel had a vmlinuz without a healthy module tree/initrd, while an older kernel still booted. GRUB’s first entry plus a hidden timeout made the broken path automatic until cleanup.

Copy-paste command set

# After booting a working kernel via Advanced options:
export DEBIAN_FRONTEND=noninteractive
uname -r
ls -1 /boot/vmlinuz* /boot/initrd.img*
ls /lib/modules
df -h /

# Rebuild initrd for kernels that still have modules (example versions)
sudo update-initramfs -c -k 7.0.0-28-generic || true
sudo update-initramfs -c -k $(uname -r)

# Drop orphan kernels apt can no longer reinstall
sudo rm -f /boot/vmlinuz-6.8.0-45-generic /boot/initrd.img-6.8.0-45-generic \
  /boot/System.map-6.8.0-45-generic /boot/config-6.8.0-45-generic

# Make GRUB interruptible again
sudo sed -i 's/^GRUB_TIMEOUT_STYLE=.*/GRUB_TIMEOUT_STYLE=menu/; s/^GRUB_TIMEOUT=.*/GRUB_TIMEOUT=5/' /etc/default/grub
sudo update-grub

echo "---- verify ----"
ls -1 /boot/vmlinuz* /boot/initrd.img*
grep -E '^GRUB_DEFAULT|^GRUB_TIMEOUT' /etc/default/grub

Reboot, confirm the plain Ubuntu entry works, and keep one older kernel around as a safety net.

← Back to Linux Notes