treewide: fix %v in cases where we should use %w

We should always use %w when using fmt.Errorf as you can use error.Is to
compare the underlying error. When printing an error the use of %w is
wrong and should be replaced with %v.

Change-Id: I741111bd91dcee4099144d2ecaffa879fdbb34a2
Reviewed-on: https://review.monogon.dev/c/monogon/+/2993
Tested-by: Jenkins CI
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
diff --git a/build/analysis/BUILD.bazel b/build/analysis/BUILD.bazel
index a13bef5..a55e759 100644
--- a/build/analysis/BUILD.bazel
+++ b/build/analysis/BUILD.bazel
@@ -63,8 +63,7 @@
 # Append some passes provided by CockroachDB.
 NOGO_PASSES += [
     "@com_github_cockroachdb_cockroach//pkg/testutils/lint/passes/errcmp",
-    # TODO(tim): Enable when fixed
-    # "@com_github_cockroachdb_cockroach//pkg/testutils/lint/passes/errwrap",
+    "@com_github_cockroachdb_cockroach//pkg/testutils/lint/passes/errwrap",
     "@com_github_cockroachdb_cockroach//pkg/testutils/lint/passes/hash",
     "@com_github_cockroachdb_cockroach//pkg/testutils/lint/passes/nilness",
     "@com_github_cockroachdb_cockroach//pkg/testutils/lint/passes/nocopy",
diff --git a/metropolis/cli/metroctl/cmd_install_ssh.go b/metropolis/cli/metroctl/cmd_install_ssh.go
index 15ced4a..56bab4c 100644
--- a/metropolis/cli/metroctl/cmd_install_ssh.go
+++ b/metropolis/cli/metroctl/cmd_install_ssh.go
@@ -147,13 +147,13 @@
 	ctx, _ := signal.NotifyContext(context.Background(), os.Interrupt)
 	conn, err := cl.Dial(ctx, address, 5*time.Second)
 	if err != nil {
-		return fmt.Errorf("error while establishing ssh connection: %v", err)
+		return fmt.Errorf("error while establishing ssh connection: %w", err)
 	}
 
 	params := makeNodeParams()
 	rawParams, err := proto.Marshal(params)
 	if err != nil {
-		return fmt.Errorf("error while marshaling node params: %v", err)
+		return fmt.Errorf("error while marshaling node params: %w", err)
 	}
 
 	const takeoverTargetPath = "/root/takeover"
@@ -188,7 +188,7 @@
 		log.Printf("Agent stderr: %q", stderrStr)
 	}
 	if err != nil {
-		return fmt.Errorf("while starting the takeover executable: %v", err)
+		return fmt.Errorf("while starting the takeover executable: %w", err)
 	}
 
 	return nil
diff --git a/metropolis/cli/metroctl/cmd_node_metrics.go b/metropolis/cli/metroctl/cmd_node_metrics.go
index f94f020..f3bde46 100644
--- a/metropolis/cli/metroctl/cmd_node_metrics.go
+++ b/metropolis/cli/metroctl/cmd_node_metrics.go
@@ -68,7 +68,7 @@
 		}
 		res, err := client.Get(fmt.Sprintf("https://%s/metrics/%s", net.JoinHostPort(n.Status.ExternalAddress, common.MetricsPort.PortString()), args[1]))
 		if err != nil {
-			return fmt.Errorf("metrics HTTP request failed: %v", err)
+			return fmt.Errorf("metrics HTTP request failed: %w", err)
 		}
 		defer res.Body.Close()
 		_, err = io.Copy(os.Stdout, res.Body)
diff --git a/metropolis/installer/main.go b/metropolis/installer/main.go
index 0863808..16de51a 100644
--- a/metropolis/installer/main.go
+++ b/metropolis/installer/main.go
@@ -223,7 +223,7 @@
 	// Look for suitable block devices, given the minimum size.
 	blkDevs, err := findInstallableBlockDevices(espDev, minSize)
 	if err != nil {
-		return fmt.Errorf(err.Error())
+		return err
 	}
 	if len(blkDevs) == 0 {
 		return fmt.Errorf("couldn't find a suitable block device")
diff --git a/metropolis/node/core/clusternet/clusternet.go b/metropolis/node/core/clusternet/clusternet.go
index 1c3c7b3..96a500d 100644
--- a/metropolis/node/core/clusternet/clusternet.go
+++ b/metropolis/node/core/clusternet/clusternet.go
@@ -230,11 +230,11 @@
 
 		if shouldAdd {
 			if err := netlink.AddrAdd(loInterface, addr); err != nil {
-				return fmt.Errorf("assigning extra loopback IP: %v", err)
+				return fmt.Errorf("assigning extra loopback IP: %w", err)
 			}
 		} else {
 			if err := netlink.AddrDel(loInterface, addr); err != nil {
-				return fmt.Errorf("removing extra loopback IP: %v", err)
+				return fmt.Errorf("removing extra loopback IP: %w", err)
 			}
 		}
 	}
diff --git a/metropolis/node/core/consensus/client/client.go b/metropolis/node/core/consensus/client/client.go
index 70e27aa..449274a 100644
--- a/metropolis/node/core/consensus/client/client.go
+++ b/metropolis/node/core/consensus/client/client.go
@@ -133,5 +133,5 @@
 	if errL != nil && errW == nil {
 		return fmt.Errorf("closing lease: %w", errL)
 	}
-	return fmt.Errorf("closing watcher: %v, closing lease: %v", errW, errL)
+	return fmt.Errorf("closing watcher: %w, closing lease: %w", errW, errL)
 }
diff --git a/metropolis/node/core/localstorage/directory_pki.go b/metropolis/node/core/localstorage/directory_pki.go
index 8df1914..75c8a2b 100644
--- a/metropolis/node/core/localstorage/directory_pki.go
+++ b/metropolis/node/core/localstorage/directory_pki.go
@@ -41,7 +41,7 @@
 	for _, d := range []*declarative.File{&p.CACertificate, &p.Certificate, &p.Key} {
 		exists, err := d.Exists()
 		if err != nil {
-			return false, fmt.Errorf("failed to check %q: %v", d.FullPath(), err)
+			return false, fmt.Errorf("failed to check %q: %w", d.FullPath(), err)
 		}
 		if !exists {
 			return false, nil
@@ -56,7 +56,7 @@
 	for _, d := range []*declarative.File{&p.CACertificate, &p.Certificate, &p.Key} {
 		exists, err := d.Exists()
 		if err != nil {
-			return false, fmt.Errorf("failed to check %q: %v", d.FullPath(), err)
+			return false, fmt.Errorf("failed to check %q: %w", d.FullPath(), err)
 		}
 		if exists {
 			return false, nil
diff --git a/metropolis/node/core/localstorage/directory_root.go b/metropolis/node/core/localstorage/directory_root.go
index 98eede9..bfacb4e 100644
--- a/metropolis/node/core/localstorage/directory_root.go
+++ b/metropolis/node/core/localstorage/directory_root.go
@@ -51,7 +51,7 @@
 	}
 
 	if err := unix.Mount("tmpfs", r.Ephemeral.FullPath(), "tmpfs", unix.MS_NODEV, ""); err != nil {
-		return fmt.Errorf("mounting /ephemeral: %v", err)
+		return fmt.Errorf("mounting /ephemeral: %w", err)
 	}
 
 	if err := unix.Mount("tmpfs", r.Run.FullPath(), "tmpfs", unix.MS_NOEXEC|unix.MS_NODEV, ""); err != nil {
diff --git a/metropolis/node/core/localstorage/storage_esp.go b/metropolis/node/core/localstorage/storage_esp.go
index fd6913a..6404725 100644
--- a/metropolis/node/core/localstorage/storage_esp.go
+++ b/metropolis/node/core/localstorage/storage_esp.go
@@ -112,13 +112,13 @@
 		if os.IsNotExist(err) {
 			return nil, ErrNoParameters
 		}
-		return nil, fmt.Errorf("%w: when reading sealed data: %v", ErrNoParameters, err)
+		return nil, fmt.Errorf("%w: when reading sealed data: %w", ErrNoParameters, err)
 	}
 
 	var config apb.NodeParameters
 	err = proto.Unmarshal(bytes, &config)
 	if err != nil {
-		return nil, fmt.Errorf("%w: when unmarshaling: %v", ErrParametersCorrupted, err)
+		return nil, fmt.Errorf("%w: when unmarshaling: %w", ErrParametersCorrupted, err)
 	}
 
 	return &config, nil
@@ -130,13 +130,13 @@
 		if os.IsNotExist(err) {
 			return nil, ErrNoDirectory
 		}
-		return nil, fmt.Errorf("%w: when reading: %v", ErrNoDirectory, err)
+		return nil, fmt.Errorf("%w: when reading: %w", ErrNoDirectory, err)
 	}
 
 	var dir cpb.ClusterDirectory
 	err = proto.Unmarshal(bytes, &dir)
 	if err != nil {
-		return nil, fmt.Errorf("%w: when unmarshaling: %v", ErrDirectoryCorrupted, err)
+		return nil, fmt.Errorf("%w: when unmarshaling: %w", ErrDirectoryCorrupted, err)
 	}
 	return &dir, nil
 }
@@ -147,13 +147,13 @@
 		if os.IsNotExist(err) {
 			return nil, nil
 		}
-		return nil, fmt.Errorf("%w: when reading: %v", ErrNetworkConfigCorrupted, err)
+		return nil, fmt.Errorf("%w: when reading: %w", ErrNetworkConfigCorrupted, err)
 	}
 
 	var netConf npb.Net
 	err = proto.Unmarshal(bytes, &netConf)
 	if err != nil {
-		return nil, fmt.Errorf("%w: when unmarshaling: %v", ErrNetworkConfigCorrupted, err)
+		return nil, fmt.Errorf("%w: when unmarshaling: %w", ErrNetworkConfigCorrupted, err)
 	}
 	return &netConf, nil
 }
@@ -204,14 +204,14 @@
 		if os.IsNotExist(err) {
 			return nil, ErrNoSealed
 		}
-		return nil, fmt.Errorf("%w: when reading sealed data: %v", ErrSealedUnavailable, err)
+		return nil, fmt.Errorf("%w: when reading sealed data: %w", ErrSealedUnavailable, err)
 	}
 
 	switch tpmUsage {
 	case cpb.NodeTPMUsage_NODE_TPM_PRESENT_AND_USED:
 		bytes, err = tpm.Unseal(bytes)
 		if err != nil {
-			return nil, fmt.Errorf("%w: when unsealing: %v", ErrSealedCorrupted, err)
+			return nil, fmt.Errorf("%w: when unsealing: %w", ErrSealedCorrupted, err)
 		}
 	case cpb.NodeTPMUsage_NODE_TPM_PRESENT_BUT_UNUSED:
 	case cpb.NodeTPMUsage_NODE_TPM_NOT_PRESENT:
@@ -222,7 +222,7 @@
 	var config ppb.SealedConfiguration
 	err = proto.Unmarshal(bytes, &config)
 	if err != nil {
-		return nil, fmt.Errorf("%w: when unmarshaling: %v", ErrSealedCorrupted, err)
+		return nil, fmt.Errorf("%w: when unmarshaling: %w", ErrSealedCorrupted, err)
 	}
 
 	return &config, nil
diff --git a/metropolis/node/core/nodeparams.go b/metropolis/node/core/nodeparams.go
index 868d070..5aa6db8 100644
--- a/metropolis/node/core/nodeparams.go
+++ b/metropolis/node/core/nodeparams.go
@@ -28,7 +28,7 @@
 	var config apb.NodeParameters
 	err = proto.Unmarshal(bytes, &config)
 	if err != nil {
-		return nil, fmt.Errorf("could not unmarshal: %v", err)
+		return nil, fmt.Errorf("could not unmarshal: %w", err)
 	}
 
 	return &config, nil
diff --git a/metropolis/node/core/roleserve/worker_heartbeat.go b/metropolis/node/core/roleserve/worker_heartbeat.go
index b543334..ba5cecc 100644
--- a/metropolis/node/core/roleserve/worker_heartbeat.go
+++ b/metropolis/node/core/roleserve/worker_heartbeat.go
@@ -43,7 +43,7 @@
 
 	for {
 		if err := stream.Send(&ipb.HeartbeatUpdateRequest{}); err != nil {
-			return fmt.Errorf("while sending a heartbeat: %v", err)
+			return fmt.Errorf("while sending a heartbeat: %w", err)
 		}
 		next := time.Now().Add(curator.HeartbeatTimeout)
 
@@ -52,7 +52,7 @@
 			return fmt.Errorf("stream closed by the server, restarting worker... ")
 		}
 		if err != nil {
-			return fmt.Errorf("while receiving a heartbeat reply: %v", err)
+			return fmt.Errorf("while receiving a heartbeat reply: %w", err)
 		}
 
 		time.Sleep(time.Until(next))
diff --git a/metropolis/node/core/rpc/resolver/resolver.go b/metropolis/node/core/rpc/resolver/resolver.go
index 316c319..c06911b 100644
--- a/metropolis/node/core/rpc/resolver/resolver.go
+++ b/metropolis/node/core/rpc/resolver/resolver.go
@@ -222,7 +222,7 @@
 	cl, err := grpc.Dial(MetropolisControlAddress, opts...)
 	if err != nil {
 		// This generally shouldn't happen.
-		return fmt.Errorf("could not dial gRPC: %v", err)
+		return fmt.Errorf("could not dial gRPC: %w", err)
 	}
 	defer cl.Close()
 
diff --git a/metropolis/node/core/tconsole/tconsole.go b/metropolis/node/core/tconsole/tconsole.go
index bd4bd08..b83a261 100644
--- a/metropolis/node/core/tconsole/tconsole.go
+++ b/metropolis/node/core/tconsole/tconsole.go
@@ -51,7 +51,7 @@
 func New(terminal Terminal, ttyPath string, lt *logtree.LogTree, network event.Value[*network.Status], roles event.Value[*cpb.NodeRoles], curatorConn event.Value[*roleserve.CuratorConnection]) (*Console, error) {
 	reader, err := lt.Read("", logtree.WithChildren(), logtree.WithStream())
 	if err != nil {
-		return nil, fmt.Errorf("lt.Read: %v", err)
+		return nil, fmt.Errorf("lt.Read: %w", err)
 	}
 
 	tty, err := tcell.NewDevTtyFromDev(ttyPath)
diff --git a/metropolis/node/core/update/update.go b/metropolis/node/core/update/update.go
index 2e30d2a..51dc737 100644
--- a/metropolis/node/core/update/update.go
+++ b/metropolis/node/core/update/update.go
@@ -271,7 +271,7 @@
 		return s.tryDownloadBundle(ctx, bundleURL, &bundleRaw)
 	}, backoff.WithContext(b, ctx))
 	if err != nil {
-		return fmt.Errorf("error downloading Metropolis bundle: %v", err)
+		return fmt.Errorf("error downloading Metropolis bundle: %w", err)
 	}
 	bundle, err := zip.NewReader(bytes.NewReader(bundleRaw.Bytes()), int64(bundleRaw.Len()))
 	if err != nil {
@@ -541,12 +541,12 @@
 		if err == nil {
 			s.Logger.Infof("Restored missing EFI boot entry for Metropolis")
 		} else {
-			return fmt.Errorf("while restoring missing EFI boot entry for Metropolis: %v", err)
+			return fmt.Errorf("while restoring missing EFI boot entry for Metropolis: %w", err)
 		}
 	}
 	bootOrder, err := efivarfs.GetBootOrder()
 	if err != nil {
-		return fmt.Errorf("failed to get EFI boot order: %v", err)
+		return fmt.Errorf("failed to get EFI boot order: %w", err)
 	}
 	for _, bentry := range bootOrder {
 		if bentry == uint16(validBootEntryIdx) {
diff --git a/metropolis/node/kubernetes/containerd/main.go b/metropolis/node/kubernetes/containerd/main.go
index 6782137..bb7e140 100644
--- a/metropolis/node/kubernetes/containerd/main.go
+++ b/metropolis/node/kubernetes/containerd/main.go
@@ -83,7 +83,7 @@
 				// is not an issue for us.
 				time.Sleep(10 * time.Millisecond)
 			} else if err != nil {
-				return fmt.Errorf("log pump failed: %v", err)
+				return fmt.Errorf("log pump failed: %w", err)
 			}
 		}
 	}
diff --git a/metropolis/node/kubernetes/plugins/kvmdevice/kvmdevice.go b/metropolis/node/kubernetes/plugins/kvmdevice/kvmdevice.go
index 4d3f4a1..d29112f 100644
--- a/metropolis/node/kubernetes/plugins/kvmdevice/kvmdevice.go
+++ b/metropolis/node/kubernetes/plugins/kvmdevice/kvmdevice.go
@@ -138,7 +138,7 @@
 
 	l1tfStatus, err := os.ReadFile("/sys/devices/system/cpu/vulnerabilities/l1tf")
 	if err != nil && !os.IsNotExist(err) {
-		return fmt.Errorf("failed to query for CPU vulnerabilities: %v", err)
+		return fmt.Errorf("failed to query for CPU vulnerabilities: %w", err)
 	}
 
 	if bytes.Contains(l1tfStatus, []byte("vulnerable")) {
@@ -164,7 +164,7 @@
 
 	err = unix.Mknod("/dev/kvm", 0660, int(kvmDevNode))
 	if err != nil && !errors.Is(err, unix.EEXIST) {
-		return fmt.Errorf("failed to create KVM device node: %v", err)
+		return fmt.Errorf("failed to create KVM device node: %w", err)
 	}
 
 	// Try to remove socket if an unclean shutdown happened
diff --git a/metropolis/node/kubernetes/reconciler/reconciler_test.go b/metropolis/node/kubernetes/reconciler/reconciler_test.go
index f457859..5116b0a 100644
--- a/metropolis/node/kubernetes/reconciler/reconciler_test.go
+++ b/metropolis/node/kubernetes/reconciler/reconciler_test.go
@@ -198,7 +198,7 @@
 		}
 
 		if err := reconcile(ctx, r, rname); err != nil {
-			return fmt.Errorf("reconcile: %v", err)
+			return fmt.Errorf("reconcile: %w", err)
 		}
 		// everything requested should have been created
 		if diff := r.currentDiff(makeTestObject("foo", 0), makeTestObject("bar", 0), makeTestObject("baz", 0)); diff != "" {
@@ -207,7 +207,7 @@
 
 		delete(r.expected, "foo")
 		if err := reconcile(ctx, r, rname); err != nil {
-			return fmt.Errorf("reconcile: %v", err)
+			return fmt.Errorf("reconcile: %w", err)
 		}
 		// foo should now be missing
 		if diff := r.currentDiff(makeTestObject("bar", 0), makeTestObject("baz", 0)); diff != "" {
@@ -216,7 +216,7 @@
 
 		r.expected["bar"] = makeTestObject("bar", 1)
 		if err := reconcile(ctx, r, rname); err != nil {
-			return fmt.Errorf("reconcile: %v", err)
+			return fmt.Errorf("reconcile: %w", err)
 		}
 		// bar should be updated
 		if diff := r.currentDiff(makeTestObject("bar", 1), makeTestObject("baz", 0)); diff != "" {
diff --git a/metropolis/test/e2e/suites/kubernetes/run_test.go b/metropolis/test/e2e/suites/kubernetes/run_test.go
index ed08203..9056ec4 100644
--- a/metropolis/test/e2e/suites/kubernetes/run_test.go
+++ b/metropolis/test/e2e/suites/kubernetes/run_test.go
@@ -182,7 +182,7 @@
 				errorMsg.WriteString(" | ")
 				errorMsg.WriteString(msg.Message)
 			}
-			return fmt.Errorf("pod is not ready: %v", errorMsg.String())
+			return fmt.Errorf("pod is not ready: %s", errorMsg.String())
 		}
 	})
 	util.TestEventual(t, "Simple StatefulSet with PVC", ctx, largeTestTimeout, func(ctx context.Context) error {
diff --git a/osbase/bringup/bringup.go b/osbase/bringup/bringup.go
index 54bbad6..66be063 100644
--- a/osbase/bringup/bringup.go
+++ b/osbase/bringup/bringup.go
@@ -61,7 +61,7 @@
 		}
 		reader, err := lt.Read("", logtree.WithChildren(), logtree.WithStream())
 		if err != nil {
-			panic(fmt.Errorf("could not set up root log reader: %v", err))
+			panic(fmt.Errorf("could not set up root log reader: %w", err))
 		}
 		go func() {
 			for {
diff --git a/osbase/fat32/fat32.go b/osbase/fat32/fat32.go
index a0b8414..e0d460f 100644
--- a/osbase/fat32/fat32.go
+++ b/osbase/fat32/fat32.go
@@ -397,7 +397,7 @@
 
 	for _, i := range p.orderedInodes {
 		if err := i.writeData(wb, bs.Label); err != nil {
-			return fmt.Errorf("failed to write inode %q: %v", i.Name, err)
+			return fmt.Errorf("failed to write inode %q: %w", i.Name, err)
 		}
 		if err := wb.FinishBlock(int64(opts.BlockSize)*int64(bs.BlocksPerCluster), false); err != nil {
 			return err
@@ -423,7 +423,7 @@
 	if opts.ID == 0 {
 		var buf [4]byte
 		if _, err := rand.Read(buf[:]); err != nil {
-			return nil, nil, nil, fmt.Errorf("failed to assign random FAT ID: %v", err)
+			return nil, nil, nil, fmt.Errorf("failed to assign random FAT ID: %w", err)
 		}
 		opts.ID = binary.BigEndian.Uint32(buf[:])
 	}
diff --git a/osbase/fsquota/fsxattrs/fsxattrs.go b/osbase/fsquota/fsxattrs/fsxattrs.go
index 135b886..8c94657 100644
--- a/osbase/fsquota/fsxattrs/fsxattrs.go
+++ b/osbase/fsquota/fsxattrs/fsxattrs.go
@@ -67,7 +67,7 @@
 	var attrs FSXAttrs
 	_, _, errno := unix.Syscall(unix.SYS_IOCTL, file.Fd(), FS_IOC_FSGETXATTR, uintptr(unsafe.Pointer(&attrs)))
 	if errno != 0 {
-		return nil, fmt.Errorf("failed to execute getFSXAttrs: %v", errno)
+		return nil, fmt.Errorf("failed to execute getFSXAttrs: %w", errno)
 	}
 	return &attrs, nil
 }
@@ -75,7 +75,7 @@
 func Set(file *os.File, attrs *FSXAttrs) error {
 	_, _, errno := unix.Syscall(unix.SYS_IOCTL, file.Fd(), FS_IOC_FSSETXATTR, uintptr(unsafe.Pointer(attrs)))
 	if errno != 0 {
-		return fmt.Errorf("failed to execute setFSXAttrs: %v", errno)
+		return fmt.Errorf("failed to execute setFSXAttrs: %w", errno)
 	}
 	return nil
 }
diff --git a/osbase/gpt/gpt.go b/osbase/gpt/gpt.go
index 1c66816..126021b 100644
--- a/osbase/gpt/gpt.go
+++ b/osbase/gpt/gpt.go
@@ -227,7 +227,7 @@
 
 	fs, _, err := gpt.GetFreeSpaces()
 	if err != nil {
-		return fmt.Errorf("unable to determine free space: %v", err)
+		return fmt.Errorf("unable to determine free space: %w", err)
 	}
 	if opts.preferEnd {
 		// Reverse fs slice to start iteration at the end
@@ -530,7 +530,7 @@
 		hdrRaw.WriteByte(0x00)
 	}
 	if _, err := gpt.b.WriteAt(hdrRaw.Bytes(), (blockCount-1)*blockSize); err != nil {
-		return fmt.Errorf("failed to write alternate header: %v", err)
+		return fmt.Errorf("failed to write alternate header: %w", err)
 	}
 
 	// Sync device after writing each GPT, to ensure there is at least one valid
@@ -640,7 +640,7 @@
 	if err != nil {
 		alternateGPT, err2 := readSingleGPT(r, r.BlockCount()-1)
 		if err2 != nil {
-			return nil, fmt.Errorf("failed to read both GPTs: primary GPT (%v), secondary GPT (%v)", err, err2)
+			return nil, fmt.Errorf("failed to read both GPTs: primary GPT (%w), secondary GPT (%w)", err, err2)
 		}
 		alternateGPT.BootCode = bootCode
 		return alternateGPT, nil
diff --git a/osbase/kexec/kexec.go b/osbase/kexec/kexec.go
index 7109903..f1f8d99 100644
--- a/osbase/kexec/kexec.go
+++ b/osbase/kexec/kexec.go
@@ -67,7 +67,7 @@
 	}
 
 	if err := unix.KexecFileLoad(int(kernel.Fd()), initramfsfd, passedCmdline, flags); err != nil {
-		return fmt.Errorf("SYS_kexec_file_load(%d, %d, %s, %x) = %v", kernel.Fd(), initramfsfd, cmdline, flags, err)
+		return fmt.Errorf("SYS_kexec_file_load(%d, %d, %s, %x) = %w", kernel.Fd(), initramfsfd, cmdline, flags, err)
 	}
 	runtime.KeepAlive(kernel)
 	runtime.KeepAlive(initramfs)
diff --git a/osbase/logtree/zap.go b/osbase/logtree/zap.go
index 82e6dda..e00109b 100644
--- a/osbase/logtree/zap.go
+++ b/osbase/logtree/zap.go
@@ -82,7 +82,7 @@
 func parseZapJSON(s string) (*zapEntry, error) {
 	entry := make(map[string]any)
 	if err := json.Unmarshal([]byte(s), &entry); err != nil {
-		return nil, fmt.Errorf("invalid JSON: %v", err)
+		return nil, fmt.Errorf("invalid JSON: %w", err)
 	}
 	message, ok := entry["message"].(string)
 	if !ok {
diff --git a/osbase/net/dns/kubernetes/object/informer.go b/osbase/net/dns/kubernetes/object/informer.go
index 8ec1f21..dee2da0 100644
--- a/osbase/net/dns/kubernetes/object/informer.go
+++ b/osbase/net/dns/kubernetes/object/informer.go
@@ -21,7 +21,7 @@
 	}
 	objMeta, err := meta.Accessor(obj)
 	if err != nil {
-		return "", fmt.Errorf("object has no meta: %v", err)
+		return "", fmt.Errorf("object has no meta: %w", err)
 	}
 	if len(objMeta.GetNamespace()) == 0 {
 		return objMeta.GetName(), nil
diff --git a/osbase/tpm/credactivation_compat.go b/osbase/tpm/credactivation_compat.go
index 24766a7..2c5ee3b 100644
--- a/osbase/tpm/credactivation_compat.go
+++ b/osbase/tpm/credactivation_compat.go
@@ -57,7 +57,7 @@
 	// Spec: TCG 2.0 EK Credential Profile revision 14, section 2.1.5.1.
 	seed := make([]byte, symBlockSize)
 	if _, err := io.ReadFull(rnd, seed); err != nil {
-		return nil, nil, fmt.Errorf("generating seed: %v", err)
+		return nil, nil, fmt.Errorf("generating seed: %w", err)
 	}
 
 	// Encrypt the seed value using the provided public key.
@@ -65,7 +65,7 @@
 	label := append([]byte(labelIdentity), 0)
 	encSecret, err := rsa.EncryptOAEP(aikHash.New(), rnd, pub, seed, label)
 	if err != nil {
-		return nil, nil, fmt.Errorf("generating encrypted seed: %v", err)
+		return nil, nil, fmt.Errorf("generating encrypted seed: %w", err)
 	}
 
 	// Generate the encrypted credential by convolving the seed with the digest
@@ -73,19 +73,19 @@
 	// See section 24.4 of TPM 2.0 specification, part 1.
 	aikNameEncoded, err := aik.Encode()
 	if err != nil {
-		return nil, nil, fmt.Errorf("encoding aikName: %v", err)
+		return nil, nil, fmt.Errorf("encoding aikName: %w", err)
 	}
 	symmetricKey, err := tpm2.KDFa(aik.Alg, seed, labelStorage, aikNameEncoded, nil, len(seed)*8)
 	if err != nil {
-		return nil, nil, fmt.Errorf("generating symmetric key: %v", err)
+		return nil, nil, fmt.Errorf("generating symmetric key: %w", err)
 	}
 	c, err := aes.NewCipher(symmetricKey)
 	if err != nil {
-		return nil, nil, fmt.Errorf("symmetric cipher setup: %v", err)
+		return nil, nil, fmt.Errorf("symmetric cipher setup: %w", err)
 	}
 	cv, err := tpmutil.Pack(tpmutil.U16Bytes(secret))
 	if err != nil {
-		return nil, nil, fmt.Errorf("generating cv (TPM2B_Digest): %v", err)
+		return nil, nil, fmt.Errorf("generating cv (TPM2B_Digest): %w", err)
 	}
 
 	// IV is all null bytes. encIdentity represents the encrypted credential.
@@ -97,7 +97,7 @@
 	// See section 24.5 of the TPM specification revision 2 part 1.
 	macKey, err := tpm2.KDFa(aik.Alg, seed, labelIntegrity, nil, nil, aikHash.Size()*8)
 	if err != nil {
-		return nil, nil, fmt.Errorf("generating HMAC key: %v", err)
+		return nil, nil, fmt.Errorf("generating HMAC key: %w", err)
 	}
 
 	mac := hmac.New(aikHash.New, macKey)
@@ -111,16 +111,16 @@
 	}
 	id, err := tpmutil.Pack(idObject)
 	if err != nil {
-		return nil, nil, fmt.Errorf("encoding IDObject: %v", err)
+		return nil, nil, fmt.Errorf("encoding IDObject: %w", err)
 	}
 
 	packedID, err := tpmutil.Pack(id)
 	if err != nil {
-		return nil, nil, fmt.Errorf("packing id: %v", err)
+		return nil, nil, fmt.Errorf("packing id: %w", err)
 	}
 	packedEncSecret, err := tpmutil.Pack(encSecret)
 	if err != nil {
-		return nil, nil, fmt.Errorf("packing encSecret: %v", err)
+		return nil, nil, fmt.Errorf("packing encSecret: %w", err)
 	}
 
 	return packedID, packedEncSecret, nil
diff --git a/osbase/tpm/eventlog/eventlog.go b/osbase/tpm/eventlog/eventlog.go
index dbfeae0..03aaf69 100644
--- a/osbase/tpm/eventlog/eventlog.go
+++ b/osbase/tpm/eventlog/eventlog.go
@@ -259,7 +259,7 @@
 		}
 		el := e.clone()
 		if err := wkrd.apply(el); err != nil {
-			return nil, fmt.Errorf("failed applying workaround %q: %v", wkrd.id, err)
+			return nil, fmt.Errorf("failed applying workaround %q: %w", wkrd.id, err)
 		}
 		if events, err := replayEvents(el.rawEvents, pcrs); err == nil {
 			return events, nil
@@ -394,12 +394,12 @@
 	var el EventLog
 	e, err := parseFn(r, specID)
 	if err != nil {
-		return nil, fmt.Errorf("parse first event: %v", err)
+		return nil, fmt.Errorf("parse first event: %w", err)
 	}
 	if e.typ == eventTypeNoAction {
 		specID, err = parseSpecIDEvent(e.data)
 		if err != nil {
-			return nil, fmt.Errorf("failed to parse spec ID event: %v", err)
+			return nil, fmt.Errorf("failed to parse spec ID event: %w", err)
 		}
 		for _, alg := range specID.algs {
 			switch tpm2.Algorithm(alg.ID) {
@@ -472,7 +472,7 @@
 		NumAlgs       uint32
 	}
 	if err := binary.Read(r, binary.LittleEndian, &header); err != nil {
-		return nil, fmt.Errorf("reading event header: %v", err)
+		return nil, fmt.Errorf("reading event header: %w", err)
 	}
 	if header.Signature != wantSignature {
 		return nil, fmt.Errorf("invalid spec id signature: %x", header.Signature)
@@ -493,14 +493,14 @@
 	var e specIDEvent
 	for i := 0; i < int(header.NumAlgs); i++ {
 		if err := binary.Read(r, binary.LittleEndian, &specAlg); err != nil {
-			return nil, fmt.Errorf("reading algorithm: %v", err)
+			return nil, fmt.Errorf("reading algorithm: %w", err)
 		}
 		e.algs = append(e.algs, specAlg)
 	}
 
 	var vendorInfoSize uint8
 	if err := binary.Read(r, binary.LittleEndian, &vendorInfoSize); err != nil {
-		return nil, fmt.Errorf("reading vender info size: %v", err)
+		return nil, fmt.Errorf("reading vender info size: %w", err)
 	}
 	if r.Len() != int(vendorInfoSize) {
 		return nil, fmt.Errorf("reading vendor info, expected %d remaining bytes, got %d", vendorInfoSize, r.Len())
@@ -600,7 +600,7 @@
 				continue
 			}
 			if uint16(r.Len()) < alg.Size {
-				return event, fmt.Errorf("reading digest: %v", io.ErrUnexpectedEOF)
+				return event, fmt.Errorf("reading digest: %w", io.ErrUnexpectedEOF)
 			}
 			digest.data = make([]byte, alg.Size)
 			digest.hash = HashAlg(alg.ID).cryptoHash()
diff --git a/osbase/tpm/eventlog/secureboot.go b/osbase/tpm/eventlog/secureboot.go
index 6fd4f1f..1e870ad 100644
--- a/osbase/tpm/eventlog/secureboot.go
+++ b/osbase/tpm/eventlog/secureboot.go
@@ -95,7 +95,7 @@
 
 		et, err := internal.UntrustedParseEventType(uint32(e.Type))
 		if err != nil {
-			return nil, fmt.Errorf("unrecognised event type: %v", err)
+			return nil, fmt.Errorf("unrecognised event type: %w", err)
 		}
 
 		digestVerify := e.digestEquals(e.Data)
@@ -109,7 +109,7 @@
 				return nil, fmt.Errorf("invalid separator data at event %d: %v", e.sequence, e.Data)
 			}
 			if digestVerify != nil {
-				return nil, fmt.Errorf("invalid separator digest at event %d: %v", e.sequence, digestVerify)
+				return nil, fmt.Errorf("invalid separator digest at event %d: %w", e.sequence, digestVerify)
 			}
 
 		case internal.EFIAction:
@@ -121,7 +121,7 @@
 		case internal.EFIVariableDriverConfig:
 			v, err := internal.ParseUEFIVariableData(bytes.NewReader(e.Data))
 			if err != nil {
-				return nil, fmt.Errorf("failed parsing EFI variable at event %d: %v", e.sequence, err)
+				return nil, fmt.Errorf("failed parsing EFI variable at event %d: %w", e.sequence, err)
 			}
 			if _, seenBefore := seenVars[v.VarName()]; seenBefore {
 				return nil, fmt.Errorf("duplicate EFI variable %q at event %d", v.VarName(), e.sequence)
@@ -132,7 +132,7 @@
 			}
 
 			if digestVerify != nil {
-				return nil, fmt.Errorf("invalid digest for variable %q on event %d: %v", v.VarName(), e.sequence, digestVerify)
+				return nil, fmt.Errorf("invalid digest for variable %q on event %d: %w", v.VarName(), e.sequence, digestVerify)
 			}
 
 			switch v.VarName() {
@@ -143,19 +143,19 @@
 				out.Enabled = v.VariableData[0] == 1
 			case "PK":
 				if out.PlatformKeys, out.PlatformKeyHashes, err = v.SignatureData(); err != nil {
-					return nil, fmt.Errorf("event %d: failed parsing platform keys: %v", e.sequence, err)
+					return nil, fmt.Errorf("event %d: failed parsing platform keys: %w", e.sequence, err)
 				}
 			case "KEK":
 				if out.ExchangeKeys, out.ExchangeKeyHashes, err = v.SignatureData(); err != nil {
-					return nil, fmt.Errorf("event %d: failed parsing key exchange keys: %v", e.sequence, err)
+					return nil, fmt.Errorf("event %d: failed parsing key exchange keys: %w", e.sequence, err)
 				}
 			case "db":
 				if out.PermittedKeys, out.PermittedHashes, err = v.SignatureData(); err != nil {
-					return nil, fmt.Errorf("event %d: failed parsing signature database: %v", e.sequence, err)
+					return nil, fmt.Errorf("event %d: failed parsing signature database: %w", e.sequence, err)
 				}
 			case "dbx":
 				if out.ForbiddenKeys, out.ForbiddenHashes, err = v.SignatureData(); err != nil {
-					return nil, fmt.Errorf("event %d: failed parsing forbidden signature database: %v", e.sequence, err)
+					return nil, fmt.Errorf("event %d: failed parsing forbidden signature database: %w", e.sequence, err)
 				}
 			}
 
@@ -172,12 +172,12 @@
 						digestVerify = e.digestEquals(e.Data[:len(e.Data)-1])
 					}
 				} else {
-					return nil, fmt.Errorf("failed parsing EFI variable authority at event %d: %v", e.sequence, err)
+					return nil, fmt.Errorf("failed parsing EFI variable authority at event %d: %w", e.sequence, err)
 				}
 			}
 			seenAuthority = true
 			if digestVerify != nil {
-				return nil, fmt.Errorf("invalid digest for authority on event %d: %v", e.sequence, digestVerify)
+				return nil, fmt.Errorf("invalid digest for authority on event %d: %w", e.sequence, digestVerify)
 			}
 			if !seenSeparator {
 				out.PreSeparatorAuthority = append(out.PreSeparatorAuthority, a.Certs...)