Repository: lxc/distrobuilder
Pull request #493 (2021-07-13 09:13:37)

Wrap errors
Signed-off-by: Thomas Hipp <thomas.hipp@canonical.com>



Patch:
diff --git a/distrobuilder/chroot.go b/distrobuilder/chroot.go
index 9773a1b..ea0b847 100644
--- a/distrobuilder/chroot.go
+++ b/distrobuilder/chroot.go
@@ -5,6 +5,7 @@ import (
 	"os"
 	"path/filepath"
 
+	"github.com/pkg/errors"
 	"go.uber.org/zap"
 	"golang.org/x/sys/unix"
 )
@@ -20,7 +21,7 @@ func getOverlay(logger *zap.SugaredLogger, cacheDir, sourceDir string) (func(),
 		}
 
 		if stat.Type == unix.XFS_SUPER_MAGIC {
-			return nil, "", fmt.Errorf("overlay not supported on xfs")
+			return nil, "", errors.Errorf("overlay not supported on xfs")
 		}
 	}
 
diff --git a/distrobuilder/main.go b/distrobuilder/main.go
index 87089b3..1c10474 100644
--- a/distrobuilder/main.go
+++ b/distrobuilder/main.go
@@ -223,7 +223,7 @@ func (c *cmdGlobal) preRunBuild(cmd *cobra.Command, args []string) error {
 		// Create and set target directory if provided
 		err := os.MkdirAll(args[1], 0755)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to create directory %q", args[1])
 		}
 		c.targetDir = args[1]
 	} else {
@@ -231,7 +231,7 @@ func (c *cmdGlobal) preRunBuild(cmd *cobra.Command, args []string) error {
 		var err error
 		c.targetDir, err = os.Getwd()
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to get working directory")
 		}
 	}
 	if isRunningBuildDir {
@@ -243,20 +243,20 @@ func (c *cmdGlobal) preRunBuild(cmd *cobra.Command, args []string) error {
 	// Create source directory if it doesn't exist
 	err := os.MkdirAll(c.sourceDir, 0755)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create directory %q", c.sourceDir)
 	}
 
 	// Get the image definition
 	c.definition, err = getDefinition(args[0], c.flagOptions)
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to get definition")
 	}
 
 	// Create cache directory if we also plan on creating LXC or LXD images
 	if !isRunningBuildDir {
 		err = os.MkdirAll(c.flagCacheDir, 0755)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to create directory %q", c.flagCacheDir)
 		}
 	}
 
@@ -312,7 +312,7 @@ func (c *cmdGlobal) preRunBuild(cmd *cobra.Command, args []string) error {
 		// running build-lxd.
 		ok, err := cmd.Flags().GetBool("vm")
 		if err != nil {
-			return err
+			return errors.Wrapf(err, `Failed to get bool value of "vm"`)
 		}
 
 		if ok {
@@ -371,7 +371,7 @@ func (c *cmdGlobal) preRunPack(cmd *cobra.Command, args []string) error {
 	// resolve path
 	c.sourceDir, err = filepath.Abs(args[1])
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to get absolute path of %q", args[1])
 	}
 
 	c.targetDir = "."
@@ -382,7 +382,7 @@ func (c *cmdGlobal) preRunPack(cmd *cobra.Command, args []string) error {
 	// Get the image definition
 	c.definition, err = getDefinition(args[0], c.flagOptions)
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to get definition")
 	}
 
 	return nil
diff --git a/distrobuilder/main_lxc.go b/distrobuilder/main_lxc.go
index 88ed5ef..59bc2b3 100644
--- a/distrobuilder/main_lxc.go
+++ b/distrobuilder/main_lxc.go
@@ -25,7 +25,7 @@ func (c *cmdLXC) commandBuild() *cobra.Command {
 		RunE: func(cmd *cobra.Command, args []string) error {
 			overlayDir, cleanup, err := c.global.getOverlayDir()
 			if err != nil {
-				return err
+				return errors.Wrap(err, "Failed to get overlay directory")
 			}
 
 			if cleanup != nil {
@@ -52,7 +52,7 @@ func (c *cmdLXC) commandPack() *cobra.Command {
 		RunE: func(cmd *cobra.Command, args []string) error {
 			overlayDir, cleanup, err := c.global.getOverlayDir()
 			if err != nil {
-				return err
+				return errors.Wrap(err, "Failed to get overlay directory")
 			}
 
 			if cleanup != nil {
@@ -66,7 +66,7 @@ func (c *cmdLXC) commandPack() *cobra.Command {
 
 			err = c.runPack(cmd, args, overlayDir)
 			if err != nil {
-				return err
+				return errors.Wrap(err, "Failed to pack image")
 			}
 
 			return c.run(cmd, args, overlayDir)
@@ -137,14 +137,14 @@ func (c *cmdLXC) run(cmd *cobra.Command, args []string, overlayDir string) error
 
 		err = generator.RunLXC(img, c.global.definition.Targets.LXC)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to run generator %q", file.Generator)
 		}
 	}
 
 	exitChroot, err := shared.SetupChroot(overlayDir,
 		c.global.definition.Environment, nil)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to setup chroot in %q", overlayDir)
 	}
 
 	addSystemdGenerator()
diff --git a/distrobuilder/main_lxd.go b/distrobuilder/main_lxd.go
index dbe05a5..3da966b 100644
--- a/distrobuilder/main_lxd.go
+++ b/distrobuilder/main_lxd.go
@@ -41,7 +41,7 @@ func (c *cmdLXD) commandBuild() *cobra.Command {
 			if c.flagVM {
 				err := c.checkVMDependencies()
 				if err != nil {
-					return err
+					return errors.Wrap(err, "Failed to check VM dependencies")
 				}
 			}
 
@@ -50,7 +50,7 @@ func (c *cmdLXD) commandBuild() *cobra.Command {
 		RunE: func(cmd *cobra.Command, args []string) error {
 			overlayDir, cleanup, err := c.global.getOverlayDir()
 			if err != nil {
-				return err
+				return errors.Wrap(err, "Failed to get overlay directory")
 			}
 
 			if cleanup != nil {
@@ -87,7 +87,7 @@ func (c *cmdLXD) commandPack() *cobra.Command {
 			if c.flagVM {
 				err := c.checkVMDependencies()
 				if err != nil {
-					return err
+					return errors.Wrap(err, "Failed to check VM dependencies")
 				}
 			}
 
@@ -96,7 +96,7 @@ func (c *cmdLXD) commandPack() *cobra.Command {
 		RunE: func(cmd *cobra.Command, args []string) error {
 			overlayDir, cleanup, err := c.global.getOverlayDir()
 			if err != nil {
-				return err
+				return errors.Wrap(err, "Failed to get overlay directory")
 			}
 
 			if cleanup != nil {
@@ -114,7 +114,7 @@ func (c *cmdLXD) commandPack() *cobra.Command {
 
 			err = c.runPack(cmd, args, overlayDir)
 			if err != nil {
-				return err
+				return errors.Wrap(err, "Failed to pack image")
 			}
 
 			return c.run(cmd, args, overlayDir)
@@ -218,12 +218,12 @@ func (c *cmdLXD) run(cmd *cobra.Command, args []string, overlayDir string) error
 
 		err := os.Mkdir(vmDir, 0755)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to create directory %q", vmDir)
 		}
 
 		imgFilename, err := shared.RenderTemplate(fmt.Sprintf("%s.raw", c.global.definition.Image.Name), c.global.definition)
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to render template")
 		}
 
 		imgFile := filepath.Join(c.global.flagCacheDir, imgFilename)
@@ -329,12 +329,12 @@ func (c *cmdLXD) run(cmd *cobra.Command, args []string, overlayDir string) error
 	if c.flagVM {
 		_, err := lxd.RunCommand("umount", "-R", vmDir)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to unmount %q", vmDir)
 		}
 
 		err = vm.umountImage()
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to unmount image")
 		}
 	}
 
@@ -352,7 +352,7 @@ func (c *cmdLXD) checkVMDependencies() error {
 	for _, dep := range dependencies {
 		_, err := exec.LookPath(dep)
 		if err != nil {
-			return fmt.Errorf("Required tool %q is missing", dep)
+			return errors.Errorf("Required tool %q is missing", dep)
 		}
 	}
 
diff --git a/distrobuilder/main_repack-windows.go b/distrobuilder/main_repack-windows.go
index ab3489d..6215573 100644
--- a/distrobuilder/main_repack-windows.go
+++ b/distrobuilder/main_repack-windows.go
@@ -48,7 +48,7 @@ func (c *cmdRepackWindows) command() *cobra.Command {
 
 			overlayDir, cleanup, err := c.global.getOverlayDir()
 			if err != nil {
-				return err
+				return errors.Wrap(err, "Failed to get overlay directory")
 			}
 
 			if cleanup != nil {
@@ -78,7 +78,7 @@ func (c *cmdRepackWindows) preRun(cmd *cobra.Command, args []string) error {
 		detectedVersion := detectWindowsVersion(filepath.Base(args[0]))
 
 		if detectedVersion == "" {
-			return fmt.Errorf("Failed to detect Windows version. Please provide the version using the --windows-version flag")
+			return errors.Errorf("Failed to detect Windows version. Please provide the version using the --windows-version flag")
 		}
 
 		c.flagWindowsVersion = detectedVersion
@@ -86,14 +86,14 @@ func (c *cmdRepackWindows) preRun(cmd *cobra.Command, args []string) error {
 		supportedVersions := []string{"w10", "2k19", "2k12", "2k16"}
 
 		if !lxd.StringInSlice(c.flagWindowsVersion, supportedVersions) {
-			return fmt.Errorf("Version must be one of %v", supportedVersions)
+			return errors.Errorf("Version must be one of %v", supportedVersions)
 		}
 	}
 
 	// Check dependencies
 	err := c.checkDependencies()
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to check dependencies")
 	}
 
 	// if an error is returned, disable the usage message
@@ -102,14 +102,14 @@ func (c *cmdRepackWindows) preRun(cmd *cobra.Command, args []string) error {
 	// Clean up cache directory before doing anything
 	err = os.RemoveAll(c.global.flagCacheDir)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to remove directory %q", c.global.flagCacheDir)
 	}
 
 	success := false
 
 	err = os.Mkdir(c.global.flagCacheDir, 0755)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create directory %q", c.global.flagCacheDir)
 	}
 	defer func() {
 		if c.global.flagCleanup && !success {
@@ -122,7 +122,7 @@ func (c *cmdRepackWindows) preRun(cmd *cobra.Command, args []string) error {
 	// Create source path
 	err = os.MkdirAll(c.global.sourceDir, 0755)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create directory %q", c.global.sourceDir)
 	}
 
 	logger.Info("Mounting Windows ISO")
@@ -130,7 +130,7 @@ func (c *cmdRepackWindows) preRun(cmd *cobra.Command, args []string) error {
 	// Mount ISO
 	_, err = lxd.RunCommand("mount", "-o", "loop", args[0], c.global.sourceDir)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to mount %q at %q", args[0], c.global.sourceDir)
 	}
 
 	success = true
@@ -154,12 +154,12 @@ func (c *cmdRepackWindows) run(cmd *cobra.Command, args []string, overlayDir str
 		if !lxd.PathExists(virtioISOPath) {
 			err := os.MkdirAll(filepath.Dir(virtioISOPath), 0755)
 			if err != nil {
-				return err
+				return errors.Wrapf(err, "Failed to create directory %q", filepath.Dir(virtioISOPath))
 			}
 
 			f, err := os.Create(virtioISOPath)
 			if err != nil {
-				return err
+				return errors.Wrapf(err, "Failed to create file %q", virtioISOPath)
 			}
 			defer f.Close()
 
@@ -169,7 +169,7 @@ func (c *cmdRepackWindows) run(cmd *cobra.Command, args []string, overlayDir str
 
 			_, err = lxd.DownloadFileHash(&client, "", nil, nil, "virtio-win.iso", virtioURL, "", nil, f)
 			if err != nil {
-				return err
+				return errors.Wrapf(err, "Failed to download %q", virtioURL)
 			}
 
 			f.Close()
@@ -179,7 +179,7 @@ func (c *cmdRepackWindows) run(cmd *cobra.Command, args []string, overlayDir str
 	if !lxd.PathExists(driverPath) {
 		err := os.MkdirAll(driverPath, 0755)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to create directory %q", driverPath)
 		}
 	}
 
@@ -188,7 +188,7 @@ func (c *cmdRepackWindows) run(cmd *cobra.Command, args []string, overlayDir str
 	// Mount driver ISO
 	_, err := lxd.RunCommand("mount", "-o", "loop", virtioISOPath, driverPath)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to mount %q at %q", virtioISOPath, driverPath)
 	}
 	defer unix.Unmount(driverPath, 0)
 
@@ -229,11 +229,11 @@ func (c *cmdRepackWindows) run(cmd *cobra.Command, args []string, overlayDir str
 	}
 
 	if bootWim == "" {
-		return fmt.Errorf("Unable to find boot.wim")
+		return errors.Errorf("Unable to find boot.wim")
 	}
 
 	if installWim == "" {
-		return fmt.Errorf("Unable to find install.wim")
+		return errors.Errorf("Unable to find install.wim")
 	}
 
 	var buf bytes.Buffer
@@ -278,7 +278,7 @@ func (c *cmdRepackWindows) run(cmd *cobra.Command, args []string, overlayDir str
 
 	_, err = lxd.RunCommand("genisoimage", "--allow-limited-size", "-l", "-no-emul-boot", "-b", "efi/microsoft/boot/efisys.bin", "-o", args[1], overlayDir)
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to generate ISO")
 	}
 
 	return nil
@@ -294,7 +294,7 @@ func (c *cmdRepackWindows) modifyWim(path string, index int) error {
 	if !lxd.PathExists(wimPath) {
 		err := os.MkdirAll(wimPath, 0755)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to create directory %q", wimPath)
 		}
 	}
 
@@ -316,19 +316,19 @@ func (c *cmdRepackWindows) modifyWim(path string, index int) error {
 	}
 
 	if dirs["filerepository"] == "" {
-		return fmt.Errorf("Failed to determine windows/system32/driverstore/filerepository path")
+		return errors.Errorf("Failed to determine windows/system32/driverstore/filerepository path")
 	}
 
 	if dirs["inf"] == "" {
-		return fmt.Errorf("Failed to determine windows/inf path")
+		return errors.Errorf("Failed to determine windows/inf path")
 	}
 
 	if dirs["config"] == "" {
-		return fmt.Errorf("Failed to determine windows/system32/config path")
+		return errors.Errorf("Failed to determine windows/system32/config path")
 	}
 
 	if dirs["drivers"] == "" {
-		return fmt.Errorf("Failed to determine windows/system32/drivers path")
+		return errors.Errorf("Failed to determine windows/system32/drivers path")
 	}
 
 	logger.Infow("Modifying WIM file", "file", filepath.Base(path), "index", index)
@@ -341,7 +341,7 @@ func (c *cmdRepackWindows) modifyWim(path string, index int) error {
 
 	_, err = lxd.RunCommand("wimlib-imagex", "unmount", wimPath, "--commit")
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to unmount WIM image")
 	}
 
 	success = true
@@ -354,7 +354,7 @@ func (c *cmdRepackWindows) checkDependencies() error {
 	for _, dep := range dependencies {
 		_, err := exec.LookPath(dep)
 		if err != nil {
-			return fmt.Errorf("Required tool %q is missing", dep)
+			return errors.Errorf("Required tool %q is missing", dep)
 		}
 	}
 
@@ -481,7 +481,7 @@ func (c *cmdRepackWindows) injectDrivers(dirs map[string]string) error {
 		if !lxd.PathExists(targetBasePath) {
 			err := os.MkdirAll(targetBasePath, 0755)
 			if err != nil {
-				return err
+				return errors.Wrapf(err, "Failed to create directory %q", targetBasePath)
 			}
 		}
 
@@ -530,7 +530,7 @@ func (c *cmdRepackWindows) injectDrivers(dirs map[string]string) error {
 
 				_, ok := ctx["classGuid"]
 				if !ok {
-					return fmt.Errorf("Failed to determine classGUID for driver %q", driver)
+					return errors.Errorf("Failed to determine classGUID for driver %q", driver)
 				}
 			}
 
diff --git a/distrobuilder/vm.go b/distrobuilder/vm.go
index f6ba300..615975e 100644
--- a/distrobuilder/vm.go
+++ b/distrobuilder/vm.go
@@ -28,7 +28,7 @@ func newVM(imageFile, rootfsDir, fs string, size uint64) (*vm, error) {
 	}
 
 	if !lxd.StringInSlice(fs, []string{"btrfs", "ext4"}) {
-		return nil, fmt.Errorf("Unsupported fs: %s", fs)
+		return nil, errors.Errorf("Unsupported fs: %s", fs)
 	}
 
 	if size == 0 {
@@ -88,7 +88,7 @@ func (v *vm) createPartitions() error {
 	for _, cmd := range args {
 		err := shared.RunCommand("sgdisk", append([]string{v.imageFile}, cmd...)...)
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to create partitions")
 		}
 	}
 
@@ -103,7 +103,7 @@ func (v *vm) mountImage() error {
 
 	stdout, err := lxd.RunCommand("losetup", "-P", "-f", "--show", v.imageFile)
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to setup loop device")
 	}
 
 	v.loopDevice = strings.TrimSpace(stdout)
@@ -113,7 +113,7 @@ func (v *vm) mountImage() error {
 
 	out, err := lxd.RunCommand("lsblk", "--raw", "--output", "MAJ:MIN", "--noheadings", v.loopDevice)
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to list block devices")
 	}
 
 	deviceNumbers := strings.Split(out, "\n")
@@ -123,19 +123,19 @@ func (v *vm) mountImage() error {
 
 		major, err := strconv.Atoi(fields[0])
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to parse %q", fields[0])
 		}
 
 		minor, err := strconv.Atoi(fields[1])
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to parse %q", fields[1])
 		}
 
 		dev := unix.Mkdev(uint32(major), uint32(minor))
 
 		err = unix.Mknod(v.getUEFIDevFile(), unix.S_IFBLK|0644, int(dev))
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to create block device %q", v.getUEFIDevFile())
 		}
 	}
 
@@ -144,19 +144,19 @@ func (v *vm) mountImage() error {
 
 		major, err := strconv.Atoi(fields[0])
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to parse %q", fields[0])
 		}
 
 		minor, err := strconv.Atoi(fields[1])
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to parse %q", fields[1])
 		}
 
 		dev := unix.Mkdev(uint32(major), uint32(minor))
 
 		err = unix.Mknod(v.getRootfsDevFile(), unix.S_IFBLK|0644, int(dev))
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to create block device %q", v.getRootfsDevFile())
 		}
 	}
 
@@ -171,21 +171,21 @@ func (v *vm) umountImage() error {
 
 	err := shared.RunCommand("losetup", "-d", v.loopDevice)
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to setup loop device")
 	}
 
 	// Make sure that p1 and p2 are also removed.
 	if lxd.PathExists(v.getUEFIDevFile()) {
 		err := os.Remove(v.getUEFIDevFile())
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to remove file %q", v.getUEFIDevFile())
 		}
 	}
 
 	if lxd.PathExists(v.getRootfsDevFile()) {
 		err := os.Remove(v.getRootfsDevFile())
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to remove file %q", v.getRootfsDevFile())
 		}
 	}
 
@@ -196,20 +196,20 @@ func (v *vm) umountImage() error {
 
 func (v *vm) createRootFS() error {
 	if v.loopDevice == "" {
-		return fmt.Errorf("Disk image not mounted")
+		return errors.Errorf("Disk image not mounted")
 	}
 
 	switch v.rootFS {
 	case "btrfs":
 		err := shared.RunCommand("mkfs.btrfs", "-f", "-L", "rootfs", v.getRootfsDevFile())
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to create btrfs filesystem")
 		}
 
 		// Create the root subvolume as well
 		err = shared.RunCommand("mount", v.getRootfsDevFile(), v.rootfsDir)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to mount %q at %q", v.getRootfsDevFile(), v.rootfsDir)
 		}
 		defer shared.RunCommand("umount", v.rootfsDir)
 
@@ -223,7 +223,7 @@ func (v *vm) createRootFS() error {
 
 func (v *vm) createUEFIFS() error {
 	if v.loopDevice == "" {
-		return fmt.Errorf("Disk image not mounted")
+		return errors.New("Disk image not mounted")
 	}
 
 	return shared.RunCommand("mkfs.vfat", "-F", "32", "-n", "UEFI", v.getUEFIDevFile())
@@ -231,7 +231,7 @@ func (v *vm) createUEFIFS() error {
 
 func (v *vm) getRootfsPartitionUUID() (string, error) {
 	if v.loopDevice == "" {
-		return "", fmt.Errorf("Disk image not mounted")
+		return "", errors.New("Disk image not mounted")
 	}
 
 	stdout, err := lxd.RunCommand("blkid", "-s", "PARTUUID", "-o", "value", v.getRootfsDevFile())
@@ -244,7 +244,7 @@ func (v *vm) getRootfsPartitionUUID() (string, error) {
 
 func (v *vm) getUEFIPartitionUUID() (string, error) {
 	if v.loopDevice == "" {
-		return "", fmt.Errorf("Disk image not mounted")
+		return "", errors.New("Disk image not mounted")
 	}
 
 	stdout, err := lxd.RunCommand("blkid", "-s", "PARTUUID", "-o", "value", v.getUEFIDevFile())
@@ -257,7 +257,7 @@ func (v *vm) getUEFIPartitionUUID() (string, error) {
 
 func (v *vm) mountRootPartition() error {
 	if v.loopDevice == "" {
-		return fmt.Errorf("Disk image not mounted")
+		return errors.New("Disk image not mounted")
 	}
 
 	switch v.rootFS {
@@ -273,14 +273,14 @@ func (v *vm) mountRootPartition() error {
 
 func (v *vm) mountUEFIPartition() error {
 	if v.loopDevice == "" {
-		return fmt.Errorf("Disk image not mounted")
+		return errors.New("Disk image not mounted")
 	}
 
 	mountpoint := filepath.Join(v.rootfsDir, "boot", "efi")
 
 	err := os.MkdirAll(mountpoint, 0755)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create directory %q", mountpoint)
 	}
 
 	return shared.RunCommand("mount", v.getUEFIDevFile(), mountpoint)
diff --git a/generators/cloud-init.go b/generators/cloud-init.go
index 7792121..eb5d9d6 100644
--- a/generators/cloud-init.go
+++ b/generators/cloud-init.go
@@ -35,14 +35,14 @@ func (g *cloudInit) RunLXC(img *image.LXCImage, target shared.DefinitionTargetLX
 			if lxd.StringInSlice(info.Name(), []string{"cloud-init-local", "cloud-config", "cloud-init", "cloud-final"}) {
 				err := os.Remove(path)
 				if err != nil {
-					return err
+					return errors.Wrapf(err, "Failed to remove file %q", path)
 				}
 			}
 
 			return nil
 		})
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to walk file tree %q", fullPath)
 		}
 	}
 
@@ -65,7 +65,7 @@ func (g *cloudInit) RunLXC(img *image.LXCImage, target shared.DefinitionTargetLX
 			if re.MatchString(info.Name()) {
 				err := os.Remove(path)
 				if err != nil {
-					return err
+					return errors.Wrapf(err, "Failed to remove file %q", path)
 				}
 			}
 
@@ -74,17 +74,21 @@ func (g *cloudInit) RunLXC(img *image.LXCImage, target shared.DefinitionTargetLX
 	}
 
 	// With systemd:
-	if !lxd.PathExists(filepath.Join(g.sourceDir, "/etc/cloud")) {
-		err := os.MkdirAll(filepath.Join(g.sourceDir, "/etc/cloud"), 0755)
+	path := filepath.Join(g.sourceDir, "/etc/cloud")
+
+	if !lxd.PathExists(path) {
+		err := os.MkdirAll(path, 0755)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to create directory %q", path)
 		}
 	}
 
 	// Create file /etc/cloud/cloud-init.disabled
-	f, err := os.Create(filepath.Join(g.sourceDir, "/etc/cloud/cloud-init.disabled"))
+	path = filepath.Join(g.sourceDir, "/etc/cloud/cloud-init.disabled")
+
+	f, err := os.Create(path)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create file %q", path)
 	}
 	defer f.Close()
 
@@ -97,7 +101,7 @@ func (g *cloudInit) RunLXD(img *image.LXDImage, target shared.DefinitionTargetLX
 
 	err := os.MkdirAll(templateDir, 0755)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create directory %q", templateDir)
 	}
 
 	var content string
@@ -129,14 +133,15 @@ config:
         control: auto{% else %}{{ config_get("user.network-config", "") }}{% endif %}
 `
 	default:
-		return fmt.Errorf("Unknown cloud-init configuration: %s", g.defFile.Name)
+		return errors.Errorf("Unknown cloud-init configuration: %s", g.defFile.Name)
 	}
 
 	template := fmt.Sprintf("cloud-init-%s.tpl", g.defFile.Name)
+	path := filepath.Join(templateDir, template)
 
-	file, err := os.Create(filepath.Join(templateDir, template))
+	file, err := os.Create(path)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create file %q", path)
 	}
 
 	defer file.Close()
@@ -153,12 +158,12 @@ config:
 	if g.defFile.Pongo {
 		tpl, err := pongo2.FromString(content)
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to parse template")
 		}
 
 		content, err = tpl.Execute(pongo2.Context{"lxd": target})
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to execute template")
 		}
 	}
 
@@ -184,7 +189,7 @@ config:
 		When:       []string{"create", "copy"},
 	}
 
-	return err
+	return nil
 }
 
 // Run does nothing.
diff --git a/generators/copy.go b/generators/copy.go
index 285adf2..eb6c7c6 100644
--- a/generators/copy.go
+++ b/generators/copy.go
@@ -7,6 +7,8 @@ import (
 	"path/filepath"
 	"strings"
 
+	"github.com/pkg/errors"
+
 	"github.com/lxc/distrobuilder/image"
 	"github.com/lxc/distrobuilder/shared"
 	lxd "github.com/lxc/lxd/shared"
@@ -44,12 +46,12 @@ func (g *copy) Run() error {
 
 	dirFiles, err := ioutil.ReadDir(filepath.Dir(srcPath))
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to read directory %q", filepath.Dir(srcPath))
 	}
 	for _, f := range dirFiles {
 		match, err := filepath.Match(srcPath, filepath.Join(filepath.Dir(srcPath), f.Name()))
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to match pattern")
 		}
 		if match {
 			files = append(files, filepath.Join(filepath.Dir(srcPath), f.Name()))
@@ -61,10 +63,7 @@ func (g *copy) Run() error {
 		// Look for the literal file
 		_, err = os.Stat(srcPath)
 		if err != nil {
-			if os.IsNotExist(err) {
-				err = fmt.Errorf("File '%s' doesn't exist", srcPath)
-			}
-			return err
+			return errors.Wrapf(err, "Failed to stat file %q", srcPath)
 		}
 		err = g.doCopy(srcPath, destPath, g.defFile)
 	case 1:
@@ -79,13 +78,17 @@ func (g *copy) Run() error {
 			}
 		}
 	}
-	return err
+	if err != nil {
+		return errors.Wrap(err, "Failed to copy file(s)")
+	}
+
+	return nil
 }
 
 func (g *copy) doCopy(srcPath, destPath string, defFile shared.DefinitionFile) error {
 	in, err := os.Stat(srcPath)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to stat file %q", srcPath)
 	}
 
 	switch in.Mode() & os.ModeType {
@@ -96,16 +99,16 @@ func (g *copy) doCopy(srcPath, destPath string, defFile shared.DefinitionFile) e
 		}
 		err := g.copyFile(srcPath, destPath, defFile)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to copy file %q to %q", srcPath, destPath)
 		}
 
 	case os.ModeDir:
 		err := g.copyDir(srcPath, destPath, defFile)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to copy file %q to %q", srcPath, destPath)
 		}
 	default:
-		return fmt.Errorf("File type of %s not supported", srcPath)
+		return errors.Errorf("File type of %q not supported", srcPath)
 	}
 
 	return nil
@@ -119,31 +122,34 @@ func (g *copy) copyDir(srcPath, destPath string, defFile shared.DefinitionFile)
 
 		rel, err := filepath.Rel(srcPath, src)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to get relative path of %q", srcPath)
 		}
 		dest := filepath.Join(destPath, rel)
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to join path elements")
 		}
 
 		switch fi.Mode() & os.ModeType {
 		case 0, os.ModeSymlink:
 			err = g.copyFile(src, dest, defFile)
 			if err != nil {
-				return err
+				return errors.Wrapf(err, "Failed to copy file %q to %q", src, dest)
 			}
 		case os.ModeDir:
 			err := os.MkdirAll(dest, os.ModePerm)
 			if err != nil {
-				return err
+				return errors.Wrapf(err, "Failed to create directory %q", dest)
 			}
 		default:
-			fmt.Printf("File type of %s not supported, skipping", src)
+			fmt.Printf("File type of %q not supported, skipping", src)
 		}
 		return nil
 	})
+	if err != nil {
+		return errors.Wrapf(err, "Failed to walk file tree of %q", srcPath)
+	}
 
-	return err
+	return nil
 }
 
 func (g *copy) copyFile(src, dest string, defFile shared.DefinitionFile) error {
@@ -154,18 +160,24 @@ func (g *copy) copyFile(src, dest string, defFile shared.DefinitionFile) error {
 		err = os.MkdirAll(dir, os.ModePerm)
 	}
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create directory %q", dir)
 	}
 
 	err = lxd.FileCopy(src, dest)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to copy file %q to %q", src, dest)
 	}
 
 	out, err := os.Open(dest)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to open file %q", dest)
 	}
 	defer out.Close()
-	return updateFileAccess(out, defFile)
+
+	err = updateFileAccess(out, defFile)
+	if err != nil {
+		return errors.Wrapf(err, "Failed to update file access of %q", dest)
+	}
+
+	return nil
 }
diff --git a/generators/dump.go b/generators/dump.go
index 4947e68..d66c85c 100644
--- a/generators/dump.go
+++ b/generators/dump.go
@@ -6,6 +6,7 @@ import (
 	"strings"
 
 	"github.com/flosch/pongo2"
+	"github.com/pkg/errors"
 
 	"github.com/lxc/distrobuilder/image"
 	"github.com/lxc/distrobuilder/shared"
@@ -22,22 +23,25 @@ func (g *dump) RunLXC(img *image.LXCImage, target shared.DefinitionTargetLXC) er
 	if g.defFile.Pongo {
 		tpl, err := pongo2.FromString(g.defFile.Content)
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to parse template")
 		}
 
 		content, err = tpl.Execute(pongo2.Context{"lxc": target})
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to execute template")
 		}
 	}
 
 	err := g.run(content)
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to dump content")
 	}
 
 	if g.defFile.Templated {
-		return img.AddTemplate(g.defFile.Path)
+		err = img.AddTemplate(g.defFile.Path)
+		if err != nil {
+			return errors.Wrap(err, "Failed to add template")
+		}
 	}
 
 	return nil
@@ -50,12 +54,12 @@ func (g *dump) RunLXD(img *image.LXDImage, target shared.DefinitionTargetLXD) er
 	if g.defFile.Pongo {
 		tpl, err := pongo2.FromString(g.defFile.Content)
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to parse template")
 		}
 
 		content, err = tpl.Execute(pongo2.Context{"lxd": target})
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to execute template")
 		}
 	}
 
@@ -73,13 +77,13 @@ func (g *dump) run(content string) error {
 	// Create any missing directory
 	err := os.MkdirAll(filepath.Dir(path), 0755)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create directory %q", filepath.Dir(path))
 	}
 
 	// Open the target file (create if needed)
 	file, err := os.Create(path)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create file %q", path)
 	}
 	defer file.Close()
 
@@ -91,8 +95,13 @@ func (g *dump) run(content string) error {
 	// Write the content
 	_, err = file.WriteString(content)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to write string to file %q", path)
+	}
+
+	err = updateFileAccess(file, g.defFile)
+	if err != nil {
+		return errors.Wrapf(err, "Failed to update file access of %q", path)
 	}
 
-	return updateFileAccess(file, g.defFile)
+	return nil
 }
diff --git a/generators/fstab.go b/generators/fstab.go
index cf031da..603aefc 100644
--- a/generators/fstab.go
+++ b/generators/fstab.go
@@ -5,6 +5,8 @@ import (
 	"os"
 	"path/filepath"
 
+	"github.com/pkg/errors"
+
 	"github.com/lxc/distrobuilder/image"
 	"github.com/lxc/distrobuilder/shared"
 )
@@ -15,14 +17,14 @@ type fstab struct {
 
 // RunLXC doesn't support the fstab generator.
 func (g *fstab) RunLXC(img *image.LXCImage, target shared.DefinitionTargetLXC) error {
-	return fmt.Errorf("fstab generator not supported for LXC")
+	return errors.New("fstab generator not supported for LXC")
 }
 
 // RunLXD writes to /etc/fstab.
 func (g *fstab) RunLXD(img *image.LXDImage, target shared.DefinitionTargetLXD) error {
 	f, err := os.Create(filepath.Join(g.sourceDir, "etc/fstab"))
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create file %q", filepath.Join(g.sourceDir, "etc/fstab"))
 	}
 	defer f.Close()
 
@@ -43,7 +45,11 @@ LABEL=UEFI    /boot/efi vfat  defaults  0 0
 	}
 
 	_, err = f.WriteString(fmt.Sprintf(content, fs, options))
-	return err
+	if err != nil {
+		return errors.Wrapf(err, "Failed to write string to file %q", filepath.Join(g.sourceDir, "etc/fstab"))
+	}
+
+	return nil
 }
 
 // Run does nothing.
diff --git a/generators/hostname.go b/generators/hostname.go
index c778044..d41a516 100644
--- a/generators/hostname.go
+++ b/generators/hostname.go
@@ -27,7 +27,7 @@ func (g *hostname) RunLXC(img *image.LXCImage, target shared.DefinitionTargetLXC
 	// Create new hostname file
 	file, err := os.Create(filepath.Join(g.sourceDir, g.defFile.Path))
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create file %q", filepath.Join(g.sourceDir, g.defFile.Path))
 	}
 	defer file.Close()
 
@@ -38,7 +38,12 @@ func (g *hostname) RunLXC(img *image.LXCImage, target shared.DefinitionTargetLXC
 	}
 
 	// Add hostname path to LXC's templates file
-	return img.AddTemplate(g.defFile.Path)
+	err = img.AddTemplate(g.defFile.Path)
+	if err != nil {
+		return errors.Wrap(err, "Failed to add template")
+	}
+
+	return nil
 }
 
 // RunLXD creates a hostname template.
@@ -53,12 +58,12 @@ func (g *hostname) RunLXD(img *image.LXDImage, target shared.DefinitionTargetLXD
 
 	err := os.MkdirAll(templateDir, 0755)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create directory %q", templateDir)
 	}
 
 	file, err := os.Create(filepath.Join(templateDir, "hostname.tpl"))
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create file %q", filepath.Join(templateDir, "hostname.tpl"))
 	}
 	defer file.Close()
 
@@ -81,7 +86,7 @@ func (g *hostname) RunLXD(img *image.LXDImage, target shared.DefinitionTargetLXD
 		}
 	}
 
-	return err
+	return nil
 }
 
 // Run does nothing.
diff --git a/generators/hosts.go b/generators/hosts.go
index 54802bb..9b2a836 100644
--- a/generators/hosts.go
+++ b/generators/hosts.go
@@ -6,6 +6,8 @@ import (
 	"path/filepath"
 	"strings"
 
+	"github.com/pkg/errors"
+
 	"github.com/lxc/distrobuilder/image"
 	"github.com/lxc/distrobuilder/shared"
 	lxd "github.com/lxc/lxd/shared"
@@ -27,7 +29,7 @@ func (g *hosts) RunLXC(img *image.LXCImage, target shared.DefinitionTargetLXC) e
 	// Read the current content
 	content, err := ioutil.ReadFile(filepath.Join(g.sourceDir, g.defFile.Path))
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to read file %q", filepath.Join(g.sourceDir, g.defFile.Path))
 	}
 
 	// Replace hostname with placeholder
@@ -40,18 +42,23 @@ func (g *hosts) RunLXC(img *image.LXCImage, target shared.DefinitionTargetLXC) e
 
 	f, err := os.Create(filepath.Join(g.sourceDir, g.defFile.Path))
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create file %q", filepath.Join(g.sourceDir, g.defFile.Path))
 	}
 	defer f.Close()
 
 	// Overwrite the file
 	_, err = f.Write(content)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to write to file %q", filepath.Join(g.sourceDir, g.defFile.Path))
 	}
 
 	// Add hostname path to LXC's templates file
-	return img.AddTemplate(g.defFile.Path)
+	err = img.AddTemplate(g.defFile.Path)
+	if err != nil {
+		errors.Wrap(err, "Failed to add template")
+	}
+
+	return nil
 }
 
 // RunLXD creates a hosts template.
@@ -67,13 +74,13 @@ func (g *hosts) RunLXD(img *image.LXDImage, target shared.DefinitionTargetLXD) e
 	// Create templates path
 	err := os.MkdirAll(templateDir, 0755)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create directory %q", templateDir)
 	}
 
 	// Read the current content
 	content, err := ioutil.ReadFile(filepath.Join(g.sourceDir, g.defFile.Path))
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to read file %q", filepath.Join(g.sourceDir, g.defFile.Path))
 	}
 
 	// Replace hostname with placeholder
@@ -87,7 +94,7 @@ func (g *hosts) RunLXD(img *image.LXDImage, target shared.DefinitionTargetLXD) e
 	// Write the template
 	err = ioutil.WriteFile(filepath.Join(templateDir, "hosts.tpl"), content, 0644)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to write file %q", filepath.Join(templateDir, "hosts.tpl"))
 	}
 
 	img.Metadata.Templates[g.defFile.Path] = &api.ImageMetadataTemplate{
@@ -103,7 +110,7 @@ func (g *hosts) RunLXD(img *image.LXDImage, target shared.DefinitionTargetLXD) e
 		}
 	}
 
-	return err
+	return nil
 }
 
 // Run does nothing.
diff --git a/generators/lxd-agent.go b/generators/lxd-agent.go
index a13a7c1..093b0bd 100644
--- a/generators/lxd-agent.go
+++ b/generators/lxd-agent.go
@@ -2,13 +2,14 @@ package generators
 
 import (
 	"bufio"
-	"errors"
 	"fmt"
 	"io/ioutil"
 	"os"
 	"path/filepath"
 	"strings"
 
+	"github.com/pkg/errors"
+
 	"github.com/lxc/distrobuilder/image"
 	"github.com/lxc/distrobuilder/shared"
 	lxd "github.com/lxc/lxd/shared"
@@ -29,13 +30,13 @@ func (g *lxdAgent) RunLXD(img *image.LXDImage, target shared.DefinitionTargetLXD
 
 	fi, err := os.Lstat(initFile)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to stat file %q", initFile)
 	}
 
 	if fi.Mode()&os.ModeSymlink != 0 {
 		linkTarget, err := os.Readlink(initFile)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to read link %q", initFile)
 		}
 
 		if strings.Contains(linkTarget, "systemd") {
@@ -89,14 +90,16 @@ StartLimitBurst=10
 WantedBy=multi-user.target
 `, systemdPath)
 
-	err := ioutil.WriteFile(filepath.Join(g.sourceDir, systemdPath, "system", "lxd-agent.service"), []byte(lxdAgentServiceUnit), 0644)
+	path := filepath.Join(g.sourceDir, systemdPath, "system", "lxd-agent.service")
+
+	err := ioutil.WriteFile(path, []byte(lxdAgentServiceUnit), 0644)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to write file %q", path)
 	}
 
-	err = os.Symlink(filepath.Join(g.sourceDir, systemdPath, "system", "lxd-agent.service"), filepath.Join(g.sourceDir, "/etc/systemd/system/multi-user.target.wants/lxd-agent.service"))
+	err = os.Symlink(path, filepath.Join(g.sourceDir, "/etc/systemd/system/multi-user.target.wants/lxd-agent.service"))
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create symlink %q", filepath.Join(g.sourceDir, "/etc/systemd/system/multi-user.target.wants/lxd-agent.service"))
 	}
 
 	lxdAgentSetupScript := `#!/bin/sh
@@ -140,9 +143,11 @@ rmdir "${PREFIX}/.mnt"
 chown -R root:root "${PREFIX}"
 `
 
-	err = ioutil.WriteFile(filepath.Join(g.sourceDir, systemdPath, "lxd-agent-setup"), []byte(lxdAgentSetupScript), 0755)
+	path = filepath.Join(g.sourceDir, systemdPath, "lxd-agent-setup")
+
+	err = ioutil.WriteFile(path, []byte(lxdAgentSetupScript), 0755)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to write file %q", path)
 	}
 
 	udevPath := filepath.Join("/", "lib", "udev", "rules.d")
@@ -154,7 +159,7 @@ chown -R root:root "${PREFIX}"
 	lxdAgentRules := `ACTION=="add", SYMLINK=="virtio-ports/org.linuxcontainers.lxd", TAG+="systemd", ACTION=="add", RUN+="/bin/systemctl start lxd-agent.service"`
 	err = ioutil.WriteFile(filepath.Join(g.sourceDir, udevPath, "99-lxd-agent.rules"), []byte(lxdAgentRules), 0400)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to write file %q", filepath.Join(g.sourceDir, udevPath, "99-lxd-agent.rules"))
 	}
 
 	return nil
@@ -182,12 +187,12 @@ depend() {
 
 	err := ioutil.WriteFile(filepath.Join(g.sourceDir, "/etc/init.d/lxd-agent"), []byte(lxdAgentScript), 0755)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to write file %q", filepath.Join(g.sourceDir, "/etc/init.d/lxd-agent"))
 	}
 
 	err = os.Symlink("/etc/init.d/lxd-agent", filepath.Join(g.sourceDir, "/etc/runlevels/default/lxd-agent"))
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create symlink %q", filepath.Join(g.sourceDir, "/etc/runlevels/default/lxd-agent"))
 	}
 
 	lxdConfigShareMountScript := `#!/sbin/openrc-run
@@ -208,12 +213,12 @@ start_pre() {
 
 	err = ioutil.WriteFile(filepath.Join(g.sourceDir, "/etc/init.d/lxd-agent-9p"), []byte(lxdConfigShareMountScript), 0755)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to write file %q", filepath.Join(g.sourceDir, "/etc/init.d/lxd-agent-9p"))
 	}
 
 	err = os.Symlink("/etc/init.d/lxd-agent-9p", filepath.Join(g.sourceDir, "/etc/runlevels/default/lxd-agent-9p"))
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create symlink %q", filepath.Join(g.sourceDir, "/etc/runlevels/default/lxd-agent-9p"))
 	}
 
 	lxdConfigShareMountVirtioFSScript := `#!/sbin/openrc-run
@@ -233,12 +238,12 @@ start_pre() {
 
 	err = ioutil.WriteFile(filepath.Join(g.sourceDir, "/etc/init.d/lxd-agent-virtiofs"), []byte(lxdConfigShareMountVirtioFSScript), 0755)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to write file %q", filepath.Join(g.sourceDir, "/etc/init.d/lxd-agent-virtiofs"))
 	}
 
 	err = os.Symlink("/etc/init.d/lxd-agent-virtiofs", filepath.Join(g.sourceDir, "/etc/runlevels/default/lxd-agent-virtiofs"))
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create symlink %q", filepath.Join(g.sourceDir, "/etc/runlevels/default/lxd-agent-virtiofs"))
 	}
 
 	return nil
@@ -258,7 +263,7 @@ exec lxd-agent
 
 	err := ioutil.WriteFile(filepath.Join(g.sourceDir, "/etc/init/lxd-agent"), []byte(lxdAgentScript), 0755)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to write file %q", filepath.Join(g.sourceDir, "/etc/init/lxd-agent"))
 	}
 
 	lxdConfigShareMountScript := `Description "LXD agent 9p mount"
@@ -287,7 +292,7 @@ exec mount -t 9p config /run/lxd_config/drive -o access=0,trans=virtio
 
 	err = ioutil.WriteFile(filepath.Join(g.sourceDir, "/etc/init/lxd-agent-9p"), []byte(lxdConfigShareMountScript), 0755)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to write file %q", filepath.Join(g.sourceDir, "/etc/init/lxd-agent-9p"))
 	}
 
 	lxdConfigShareMountVirtioFSScript := `Description "LXD agent virtio-fs mount"
@@ -311,7 +316,7 @@ exec mount -t virtiofs config /run/lxd_config/drive
 
 	err = ioutil.WriteFile(filepath.Join(g.sourceDir, "/etc/init/lxd-agent-virtiofs"), []byte(lxdConfigShareMountVirtioFSScript), 0755)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to write file %q", filepath.Join(g.sourceDir, "/etc/init/lxd-agent-virtiofs"))
 	}
 
 	return nil
@@ -320,7 +325,7 @@ exec mount -t virtiofs config /run/lxd_config/drive
 func (g *lxdAgent) getInitSystemFromInittab() error {
 	f, err := os.Open(filepath.Join(g.sourceDir, "etc", "inittab"))
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to open file %q", filepath.Join(g.sourceDir, "etc", "inittab"))
 	}
 	defer f.Close()
 
diff --git a/generators/template.go b/generators/template.go
index 0001a6e..9c7ea1b 100644
--- a/generators/template.go
+++ b/generators/template.go
@@ -30,13 +30,13 @@ func (g *template) RunLXD(img *image.LXDImage, target shared.DefinitionTargetLXD
 
 	err := os.MkdirAll(templateDir, 0755)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create directory %q", templateDir)
 	}
 	template := fmt.Sprintf("%s.tpl", g.defFile.Name)
 
 	file, err := os.Create(filepath.Join(templateDir, template))
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create file %q", filepath.Join(templateDir, template))
 	}
 
 	defer file.Close()
@@ -51,12 +51,12 @@ func (g *template) RunLXD(img *image.LXDImage, target shared.DefinitionTargetLXD
 	if g.defFile.Pongo {
 		tpl, err := pongo2.FromString(content)
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to parse template")
 		}
 
 		content, err = tpl.Execute(pongo2.Context{"lxd": target})
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to execute template")
 		}
 	}
 
@@ -79,7 +79,7 @@ func (g *template) RunLXD(img *image.LXDImage, target shared.DefinitionTargetLXD
 		}
 	}
 
-	return err
+	return nil
 }
 
 // Run does nothing.
diff --git a/image/lxc.go b/image/lxc.go
index 15198eb..49a63bc 100644
--- a/image/lxc.go
+++ b/image/lxc.go
@@ -48,7 +48,7 @@ func (l *LXCImage) AddTemplate(path string) error {
 	file, err := os.OpenFile(filepath.Join(metaDir, "templates"),
 		os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to open file %q", filepath.Join(metaDir, "templates"))
 	}
 	defer file.Close()
 
@@ -64,17 +64,17 @@ func (l *LXCImage) AddTemplate(path string) error {
 func (l *LXCImage) Build() error {
 	err := l.createMetadata()
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to create metadata")
 	}
 
 	err = l.packMetadata()
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to pack metadata")
 	}
 
 	err = shared.Pack(filepath.Join(l.targetDir, "rootfs.tar"), "xz", l.sourceDir, ".")
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to pack %q", filepath.Join(l.targetDir, "rootfs.tar"))
 	}
 
 	return nil
@@ -105,22 +105,22 @@ func (l *LXCImage) createMetadata() error {
 			case "all":
 				err := l.writeConfig(i, filepath.Join(metaDir, "config"), c.Content)
 				if err != nil {
-					return err
+					return errors.Wrapf(err, "Failed to write config %q", filepath.Join(metaDir, "config"))
 				}
 
 				err = l.writeConfig(i, filepath.Join(metaDir, "config-user"), c.Content)
 				if err != nil {
-					return err
+					return errors.Wrapf(err, "Failed to write config %q", filepath.Join(metaDir, "config-user"))
 				}
 			case "system":
 				err := l.writeConfig(i, filepath.Join(metaDir, "config"), c.Content)
 				if err != nil {
-					return err
+					return errors.Wrapf(err, "Failed to write config %q", filepath.Join(metaDir, "config"))
 				}
 			case "user":
 				err := l.writeConfig(i, filepath.Join(metaDir, "config-user"), c.Content)
 				if err != nil {
-					return err
+					return errors.Wrapf(err, "Failed to write config %q", filepath.Join(metaDir, "config-user"))
 				}
 			}
 		}
@@ -174,7 +174,7 @@ func (l *LXCImage) packMetadata() error {
 	// Get all config and config-user files
 	configs, err := filepath.Glob(filepath.Join(l.cacheDir, "metadata", "config*"))
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to match file pattern")
 	}
 
 	for _, c := range configs {
@@ -201,19 +201,19 @@ func (l *LXCImage) writeMetadata(filename, content string, appendContent bool) e
 	if appendContent {
 		file, err = os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to open file %q", filename)
 		}
 	} else {
 		file, err = os.Create(filename)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to create file %q", filename)
 		}
 	}
 	defer file.Close()
 
 	out, err := shared.RenderTemplate(content, l.definition)
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to render template")
 	}
 
 	// Append final new line if missing
@@ -224,7 +224,7 @@ func (l *LXCImage) writeMetadata(filename, content string, appendContent bool) e
 	// Write the content
 	_, err = file.WriteString(out)
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to write string")
 	}
 
 	return nil
diff --git a/image/lxd.go b/image/lxd.go
index 429fa44..62de7c0 100644
--- a/image/lxd.go
+++ b/image/lxd.go
@@ -52,7 +52,7 @@ func (l *LXDImage) Build(unified bool, compression string, vm bool) error {
 
 	data, err := yaml.Marshal(l.Metadata)
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to marshal yaml")
 	}
 
 	_, err = file.Write(data)
@@ -86,7 +86,7 @@ func (l *LXDImage) Build(unified bool, compression string, vm bool) error {
 			rawImage,
 			qcowImage)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to create qcow2 image %q", qcowImage)
 		}
 		defer func() {
 			os.RemoveAll(rawImage)
@@ -100,7 +100,7 @@ func (l *LXDImage) Build(unified bool, compression string, vm bool) error {
 			// Rename image to rootfs.img
 			err = os.Rename(qcowImage, filepath.Join(filepath.Dir(qcowImage), "rootfs.img"))
 			if err != nil {
-				return err
+				return errors.Wrapf(err, "Failed to rename image %q -> %q", qcowImage, filepath.Join(filepath.Dir(qcowImage), "rootfs.img"))
 			}
 
 			err = shared.Pack(targetTarball, "", l.cacheDir, "rootfs.img")
@@ -110,7 +110,7 @@ func (l *LXDImage) Build(unified bool, compression string, vm bool) error {
 				"", l.sourceDir, "--transform", "s,^./,rootfs/,", ".")
 		}
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to pack tarball %q", targetTarball)
 		}
 		defer func() {
 			if vm {
@@ -121,7 +121,7 @@ func (l *LXDImage) Build(unified bool, compression string, vm bool) error {
 		// Add the metadata to the tarball which is located in the cache directory
 		err = shared.PackUpdate(targetTarball, compression, l.cacheDir, paths...)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to add metadata to tarball %q", targetTarball)
 		}
 	} else {
 		if vm {
@@ -161,17 +161,17 @@ func (l *LXDImage) createMetadata() error {
 	l.Metadata.Properties["description"], err = shared.RenderTemplate(
 		l.definition.Image.Description, l.definition)
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to render template")
 	}
 
 	l.Metadata.Properties["name"], err = shared.RenderTemplate(
 		l.definition.Image.Name, l.definition)
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to render template")
 	}
 
 	l.Metadata.ExpiryDate = shared.GetExpiryDate(time.Now(),
 		l.definition.Image.Expiry).Unix()
 
-	return err
+	return nil
 }
diff --git a/managers/apt.go b/managers/apt.go
index 0b1c636..2cd36cf 100644
--- a/managers/apt.go
+++ b/managers/apt.go
@@ -10,6 +10,7 @@ import (
 	"strings"
 
 	lxd "github.com/lxc/lxd/shared"
+	"github.com/pkg/errors"
 
 	"github.com/lxc/distrobuilder/shared"
 )
@@ -68,49 +69,49 @@ func (m *apt) manageRepository(repoAction shared.DefinitionPackagesRepository) e
 	if !lxd.PathExists(filepath.Dir(targetFile)) {
 		err := os.MkdirAll(filepath.Dir(targetFile), 0755)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to create directory %q", filepath.Dir(targetFile))
 		}
 	}
 
 	f, err := os.OpenFile(targetFile, os.O_CREATE|os.O_RDWR, 0644)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to open file %q", targetFile)
 	}
 	defer f.Close()
 
 	content, err := ioutil.ReadAll(f)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to read from file %q", targetFile)
 	}
 
 	// Truncate file if it's not generated by distrobuilder
 	if !strings.HasPrefix(string(content), "# Generated by distrobuilder\n") {
 		err = f.Truncate(0)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to truncate %q", targetFile)
 		}
 
 		_, err = f.Seek(0, 0)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to seek on file %q", targetFile)
 		}
 
 		_, err = f.WriteString("# Generated by distrobuilder\n")
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to write to file %q", targetFile)
 		}
 	}
 
 	_, err = f.WriteString(repoAction.URL)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to write to file %q", targetFile)
 	}
 
 	// Append final new line if missing
 	if !strings.HasSuffix(repoAction.URL, "\n") {
 		_, err = f.WriteString("\n")
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to write to file %q", targetFile)
 		}
 	}
 
@@ -123,14 +124,14 @@ func (m *apt) manageRepository(repoAction shared.DefinitionPackagesRepository) e
 			// If only key ID is provided, we need gpg to be installed early.
 			_, err := lxd.RunCommand("gpg", "--recv-keys", repoAction.Key)
 			if err != nil {
-				return err
+				return errors.Wrap(err, "Failed to receive GPG keys")
 			}
 
 			var buf bytes.Buffer
 
 			err = lxd.RunCommandWithFds(nil, &buf, "gpg", "--export", "--armor", repoAction.Key)
 			if err != nil {
-				return err
+				return errors.Wrap(err, "Failed to export GPG keys")
 			}
 
 			reader = &buf
@@ -140,13 +141,13 @@ func (m *apt) manageRepository(repoAction shared.DefinitionPackagesRepository) e
 
 		f, err := os.Create(signatureFilePath)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to create file %q", signatureFilePath)
 		}
 		defer f.Close()
 
 		_, err = io.Copy(f, reader)
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to copy file")
 		}
 	}
 
diff --git a/managers/equo.go b/managers/equo.go
index d66e0b1..8a81044 100644
--- a/managers/equo.go
+++ b/managers/equo.go
@@ -1,7 +1,7 @@
 package managers
 
 import (
-	"fmt"
+	"github.com/pkg/errors"
 
 	"github.com/lxc/distrobuilder/shared"
 )
@@ -48,7 +48,7 @@ func (m *equo) manageRepository(repoAction shared.DefinitionPackagesRepository)
 		return m.enmanRepoCaller(repoAction)
 	}
 
-	return fmt.Errorf("Invalid repository Type")
+	return errors.New("Invalid repository Type")
 }
 
 func (m *equo) enmanRepoCaller(repo shared.DefinitionPackagesRepository) error {
@@ -57,7 +57,7 @@ func (m *equo) enmanRepoCaller(repo shared.DefinitionPackagesRepository) error {
 	}
 
 	if repo.Name == "" && repo.URL == "" {
-		return fmt.Errorf("Missing both repository url and repository name")
+		return errors.New("Missing both repository url and repository name")
 	}
 
 	if repo.URL != "" {
@@ -71,11 +71,11 @@ func (m *equo) enmanRepoCaller(repo shared.DefinitionPackagesRepository) error {
 
 func (m *equo) equoRepoCaller(repo shared.DefinitionPackagesRepository) error {
 	if repo.Name == "" {
-		return fmt.Errorf("Invalid repository name")
+		return errors.New("Invalid repository name")
 	}
 
 	if repo.URL == "" {
-		return fmt.Errorf("Invalid repository url")
+		return errors.New("Invalid repository url")
 	}
 
 	return shared.RunCommand("equo", "repo", "add", "--repo", repo.URL, "--pkg", repo.URL,
diff --git a/managers/luet.go b/managers/luet.go
index ef8de99..779bc5b 100644
--- a/managers/luet.go
+++ b/managers/luet.go
@@ -1,12 +1,12 @@
 package managers
 
 import (
-	"fmt"
 	"os"
 	"path/filepath"
 	"strings"
 
 	lxd "github.com/lxc/lxd/shared"
+	"github.com/pkg/errors"
 
 	"github.com/lxc/distrobuilder/shared"
 )
@@ -50,11 +50,11 @@ func (m *luet) manageRepository(repoAction shared.DefinitionPackagesRepository)
 	var targetFile string
 
 	if repoAction.Name == "" {
-		return fmt.Errorf("Invalid repository name")
+		return errors.New("Invalid repository name")
 	}
 
 	if repoAction.URL == "" {
-		return fmt.Errorf("Invalid repository url")
+		return errors.New("Invalid repository url")
 	}
 
 	if strings.HasSuffix(repoAction.Name, ".yml") {
@@ -66,20 +66,20 @@ func (m *luet) manageRepository(repoAction shared.DefinitionPackagesRepository)
 	if !lxd.PathExists(filepath.Dir(targetFile)) {
 		err := os.MkdirAll(filepath.Dir(targetFile), 0755)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to create directory %q", filepath.Dir(targetFile))
 		}
 	}
 
 	f, err := os.OpenFile(targetFile, os.O_CREATE|os.O_WRONLY, 0644)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to open file %q", targetFile)
 	}
 	defer f.Close()
 
 	// NOTE: repo.URL is not an URL but the content of the file.
 	_, err = f.WriteString(repoAction.URL)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to write string to %q", targetFile)
 	}
 
 	return nil
diff --git a/managers/manager.go b/managers/manager.go
index 2db6c7d..8e6991f 100644
--- a/managers/manager.go
+++ b/managers/manager.go
@@ -10,7 +10,7 @@ import (
 )
 
 // ErrUnknownManager represents the unknown manager error
-var ErrUnknownManager = errors.Errorf("Unknown manager")
+var ErrUnknownManager = errors.New("Unknown manager")
 
 // managerFlags represents flags for all subcommands of a package manager.
 type managerFlags struct {
@@ -109,13 +109,13 @@ func (m *Manager) ManagePackages(imageTarget shared.ImageTarget) error {
 
 	err := m.mgr.refresh()
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to refresh")
 	}
 
 	if m.def.Packages.Update {
 		err = m.mgr.update()
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to update")
 		}
 
 		// Run post update hook
@@ -134,14 +134,14 @@ func (m *Manager) ManagePackages(imageTarget shared.ImageTarget) error {
 			err = m.mgr.remove(set.Packages, set.Flags)
 		}
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to %s packages", set.Action)
 		}
 	}
 
 	if m.def.Packages.Cleanup {
 		err = m.mgr.clean()
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to clean up packages")
 		}
 	}
 
@@ -164,13 +164,13 @@ func (m *Manager) ManageRepositories(imageTarget shared.ImageTarget) error {
 		// Run template on repo.URL
 		repo.URL, err = shared.RenderTemplate(repo.URL, m.def)
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to render template")
 		}
 
 		// Run template on repo.Key
 		repo.Key, err = shared.RenderTemplate(repo.Key, m.def)
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to render template")
 		}
 
 		err = m.mgr.manageRepository(repo)
diff --git a/managers/pacman.go b/managers/pacman.go
index 96c060d..31fad8d 100644
--- a/managers/pacman.go
+++ b/managers/pacman.go
@@ -118,7 +118,7 @@ func (m *pacman) setupTrustedKeys() error {
 func (m *pacman) setMirrorlist() error {
 	f, err := os.Create(filepath.Join("etc", "pacman.d", "mirrorlist"))
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create file %q", filepath.Join("etc", "pacman.d", "mirrorlist"))
 	}
 	defer f.Close()
 
@@ -132,7 +132,7 @@ func (m *pacman) setMirrorlist() error {
 
 	_, err = f.WriteString(mirror)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to write to %q", filepath.Join("etc", "pacman.d", "mirrorlist"))
 	}
 
 	return nil
diff --git a/managers/yum.go b/managers/yum.go
index 1d15cf4..b8e0205 100644
--- a/managers/yum.go
+++ b/managers/yum.go
@@ -9,6 +9,7 @@ import (
 	"strings"
 
 	lxd "github.com/lxc/lxd/shared"
+	"github.com/pkg/errors"
 
 	"github.com/lxc/distrobuilder/shared"
 )
@@ -76,26 +77,26 @@ func yumManageRepository(repoAction shared.DefinitionPackagesRepository) error {
 	if !lxd.PathExists(filepath.Dir(targetFile)) {
 		err := os.MkdirAll(filepath.Dir(targetFile), 0755)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to create directory %q", filepath.Dir(targetFile))
 		}
 	}
 
 	f, err := os.Create(targetFile)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create file %q", targetFile)
 	}
 	defer f.Close()
 
 	_, err = f.WriteString(repoAction.URL)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to write to file %q", targetFile)
 	}
 
 	// Append final new line if missing
 	if !strings.HasSuffix(repoAction.URL, "\n") {
 		_, err = f.WriteString("\n")
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to write to file %q", targetFile)
 		}
 	}
 
diff --git a/managers/zypper.go b/managers/zypper.go
index 4781236..fde2199 100644
--- a/managers/zypper.go
+++ b/managers/zypper.go
@@ -1,7 +1,7 @@
 package managers
 
 import (
-	"fmt"
+	"github.com/pkg/errors"
 
 	"github.com/lxc/distrobuilder/shared"
 )
@@ -49,15 +49,15 @@ func (m *zypper) load() error {
 
 func (m *zypper) manageRepository(repoAction shared.DefinitionPackagesRepository) error {
 	if repoAction.Type != "" && repoAction.Type != "zypper" {
-		return fmt.Errorf("Invalid repository Type")
+		return errors.New("Invalid repository Type")
 	}
 
 	if repoAction.Name == "" {
-		return fmt.Errorf("Invalid repository name")
+		return errors.New("Invalid repository name")
 	}
 
 	if repoAction.URL == "" {
-		return fmt.Errorf("Invalid repository url")
+		return errors.New("Invalid repository url")
 	}
 
 	return shared.RunCommand("zypper", "ar", "--refresh", "--check", repoAction.URL, repoAction.Name)
diff --git a/shared/chroot.go b/shared/chroot.go
index 263f707..2818499 100644
--- a/shared/chroot.go
+++ b/shared/chroot.go
@@ -30,7 +30,7 @@ func setupMounts(rootfs string, mounts []ChrootMount) error {
 	// Create a temporary mount path
 	err := os.MkdirAll(filepath.Join(rootfs, ".distrobuilder"), 0700)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create directory %q", filepath.Join(rootfs, ".distrobuilder"))
 	}
 
 	for i, mount := range mounts {
@@ -41,12 +41,12 @@ func setupMounts(rootfs string, mounts []ChrootMount) error {
 		if mount.IsDir {
 			err := os.MkdirAll(tmpTarget, 0755)
 			if err != nil {
-				return err
+				return errors.Wrapf(err, "Failed to create directory %q", tmpTarget)
 			}
 		} else {
 			f, err := os.Create(tmpTarget)
 			if err != nil {
-				return err
+				return errors.Wrapf(err, "Failed to create file %q", tmpTarget)
 			}
 			f.Close()
 		}
@@ -96,14 +96,14 @@ func moveMounts(mounts []ChrootMount) error {
 			// Get information on current target
 			fi, err := os.Lstat(targetDir)
 			if err != nil {
-				return err
+				return errors.Wrapf(err, "Failed to stat directory %q", targetDir)
 			}
 
 			// If a symlink, resolve it
 			if fi.Mode()&os.ModeSymlink != 0 {
 				newTarget, err := os.Readlink(targetDir)
 				if err != nil {
-					return err
+					return errors.Wrapf(err, "Failed to get destination of %q", targetDir)
 				}
 
 				targetDir = newTarget
@@ -113,19 +113,19 @@ func moveMounts(mounts []ChrootMount) error {
 		// Create parent paths if missing
 		err := os.MkdirAll(targetDir, 0755)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to create directory %q", targetDir)
 		}
 
 		// Create target path
 		if mount.IsDir {
 			err = os.MkdirAll(target, 0755)
 			if err != nil {
-				return err
+				return errors.Wrapf(err, "Failed to create directory %q", target)
 			}
 		} else {
 			f, err := os.Create(target)
 			if err != nil {
-				return err
+				return errors.Wrapf(err, "Failed to create file %q", target)
 			}
 			f.Close()
 		}
@@ -140,7 +140,7 @@ func moveMounts(mounts []ChrootMount) error {
 	// Cleanup our temporary path
 	err := os.RemoveAll(filepath.Join("/", ".distrobuilder"))
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to remove directory %q", filepath.Join("/", ".distrobuilder"))
 	}
 
 	return nil
@@ -151,12 +151,12 @@ func killChrootProcesses(rootfs string) error {
 	// List all files under /proc
 	proc, err := os.Open(filepath.Join(rootfs, "proc"))
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to open file %q", filepath.Join(rootfs, "proc"))
 	}
 
 	dirs, err := proc.Readdirnames(0)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to read directory content of %q", filepath.Join(rootfs, "proc"))
 	}
 
 	// Get all processes and kill them
@@ -308,7 +308,7 @@ exit 101
 		if policyCleanup {
 			err = os.Remove("/usr/sbin/policy-rc.d")
 			if err != nil {
-				return err
+				return errors.Wrapf(err, "Failed to remove %q", "/usr/sbin/policy-rc.d")
 			}
 		}
 
@@ -318,17 +318,17 @@ exit 101
 		// Switch back to the host rootfs
 		err = root.Chdir()
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to chdir")
 		}
 
 		err = unix.Chroot(".")
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to chroot")
 		}
 
 		err = unix.Chdir(cwd)
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to chdir")
 		}
 
 		// This will kill all processes in the chroot and allow to cleanly
@@ -343,7 +343,7 @@ exit 101
 		// Wipe $rootfs/dev
 		err := os.RemoveAll(devPath)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to remove directory %q", devPath)
 		}
 
 		ActiveChroots[rootfs] = nil
diff --git a/shared/definition.go b/shared/definition.go
index 699a5df..205266e 100644
--- a/shared/definition.go
+++ b/shared/definition.go
@@ -1,7 +1,6 @@
 package shared
 
 import (
-	"fmt"
 	"reflect"
 	"strconv"
 	"strings"
@@ -236,25 +235,25 @@ func (d *Definition) SetValue(key string, value string) error {
 	// Walk through the definition and find the field with the given key
 	field, err := getFieldByTag(reflect.ValueOf(d).Elem(), reflect.TypeOf(d).Elem(), key)
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to get field by tag")
 	}
 
 	// Fail if the field cannot be set
 	if !field.CanSet() {
-		return fmt.Errorf("Cannot set value for %s", key)
+		return errors.Errorf("Cannot set value for %s", key)
 	}
 
 	switch field.Kind() {
 	case reflect.Bool:
 		v, err := strconv.ParseBool(value)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to parse bool %q", value)
 		}
 		field.SetBool(v)
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 		v, err := strconv.ParseInt(value, 10, 64)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to parse int %q", value)
 		}
 		field.SetInt(v)
 	case reflect.String:
@@ -262,11 +261,11 @@ func (d *Definition) SetValue(key string, value string) error {
 	case reflect.Uint, reflect.Uintptr, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 		v, err := strconv.ParseUint(value, 10, 64)
 		if err != nil {
-			return err
+			return errors.Wrapf(err, "Failed to parse uint %q", value)
 		}
 		field.SetUint(v)
 	default:
-		return fmt.Errorf("Unsupported type '%s'", field.Kind())
+		return errors.Errorf("Unsupported type '%s'", field.Kind())
 	}
 
 	return nil
@@ -343,7 +342,7 @@ func (d *Definition) Validate() error {
 		"rockylinux-http",
 	}
 	if !shared.StringInSlice(strings.TrimSpace(d.Source.Downloader), validDownloaders) {
-		return fmt.Errorf("source.downloader must be one of %v", validDownloaders)
+		return errors.Errorf("source.downloader must be one of %v", validDownloaders)
 	}
 
 	if d.Packages.Manager != "" {
@@ -362,35 +361,35 @@ func (d *Definition) Validate() error {
 			"luet",
 		}
 		if !shared.StringInSlice(strings.TrimSpace(d.Packages.Manager), validManagers) {
-			return fmt.Errorf("packages.manager must be one of %v", validManagers)
+			return errors.Errorf("packages.manager must be one of %v", validManagers)
 		}
 
 		if d.Packages.CustomManager != nil {
-			return fmt.Errorf("cannot have both packages.manager and packages.custom-manager set")
+			return errors.New("cannot have both packages.manager and packages.custom-manager set")
 		}
 	} else {
 		if d.Packages.CustomManager == nil {
-			return fmt.Errorf("packages.manager or packages.custom-manager needs to be set")
+			return errors.New("packages.manager or packages.custom-manager needs to be set")
 		}
 
 		if d.Packages.CustomManager.Clean.Command == "" {
-			return fmt.Errorf("packages.custom-manager requires a clean command")
+			return errors.New("packages.custom-manager requires a clean command")
 		}
 
 		if d.Packages.CustomManager.Install.Command == "" {
-			return fmt.Errorf("packages.custom-manager requires an install command")
+			return errors.New("packages.custom-manager requires an install command")
 		}
 
 		if d.Packages.CustomManager.Remove.Command == "" {
-			return fmt.Errorf("packages.custom-manager requires a remove command")
+			return errors.New("packages.custom-manager requires a remove command")
 		}
 
 		if d.Packages.CustomManager.Refresh.Command == "" {
-			return fmt.Errorf("packages.custom-manager requires a refresh command")
+			return errors.New("packages.custom-manager requires a refresh command")
 		}
 
 		if d.Packages.CustomManager.Update.Command == "" {
-			return fmt.Errorf("packages.custom-manager requires an update command")
+			return errors.New("packages.custom-manager requires an update command")
 		}
 	}
 
@@ -409,7 +408,7 @@ func (d *Definition) Validate() error {
 
 	for _, file := range d.Files {
 		if !shared.StringInSlice(strings.TrimSpace(file.Generator), validGenerators) {
-			return fmt.Errorf("files.*.generator must be one of %v", validGenerators)
+			return errors.Errorf("files.*.generator must be one of %v", validGenerators)
 		}
 	}
 
@@ -429,7 +428,7 @@ func (d *Definition) Validate() error {
 	architectureMap := strings.TrimSpace(d.Mappings.ArchitectureMap)
 	if architectureMap != "" {
 		if !shared.StringInSlice(architectureMap, validMappings) {
-			return fmt.Errorf("mappings.architecture_map must be one of %v", validMappings)
+			return errors.Errorf("mappings.architecture_map must be one of %v", validMappings)
 		}
 	}
 
@@ -442,7 +441,7 @@ func (d *Definition) Validate() error {
 
 	for _, action := range d.Actions {
 		if !shared.StringInSlice(action.Trigger, validTriggers) {
-			return fmt.Errorf("actions.*.trigger must be one of %v", validTriggers)
+			return errors.Errorf("actions.*.trigger must be one of %v", validTriggers)
 		}
 	}
 
@@ -453,14 +452,14 @@ func (d *Definition) Validate() error {
 
 	for _, set := range d.Packages.Sets {
 		if !shared.StringInSlice(set.Action, validPackageActions) {
-			return fmt.Errorf("packages.*.set.*.action must be one of %v", validPackageActions)
+			return errors.Errorf("packages.*.set.*.action must be one of %v", validPackageActions)
 		}
 	}
 
 	// Mapped architecture (distro name)
 	archMapped, err := d.getMappedArchitecture()
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to get mapped architecture")
 	}
 
 	d.Image.ArchitectureMapped = archMapped
@@ -468,19 +467,19 @@ func (d *Definition) Validate() error {
 	// Kernel architecture and personality
 	archID, err := lxdarch.ArchitectureId(d.Image.Architecture)
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to get architecture ID")
 	}
 
 	archName, err := lxdarch.ArchitectureName(archID)
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to get architecture name")
 	}
 
 	d.Image.ArchitectureKernel = archName
 
 	archPersonality, err := lxdarch.ArchitecturePersonality(archID)
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to get architecture personality")
 	}
 
 	d.Image.ArchitecturePersonality = archPersonality
diff --git a/shared/net.go b/shared/net.go
index 2c8be8e..9c9cc9f 100644
--- a/shared/net.go
+++ b/shared/net.go
@@ -78,7 +78,7 @@ func DownloadHash(def DefinitionImage, file, checksum string, hashFunc hash.Hash
 			}
 
 			if hash == "" {
-				return "", fmt.Errorf("Hash mismatch for %s: %s != %v", imagePath, result, hashes)
+				return "", errors.Errorf("Hash mismatch for %s: %s != %v", imagePath, result, hashes)
 			}
 		}
 
@@ -161,5 +161,5 @@ func downloadChecksum(targetDir string, URL string, fname string, hashFunc hash.
 		return checksum, nil
 	}
 
-	return nil, fmt.Errorf("Could not find checksum")
+	return nil, errors.New("Could not find checksum")
 }
diff --git a/shared/osarch.go b/shared/osarch.go
index 8cd75a9..1e86ea5 100644
--- a/shared/osarch.go
+++ b/shared/osarch.go
@@ -1,9 +1,8 @@
 package shared
 
 import (
-	"fmt"
-
 	"github.com/lxc/lxd/shared/osarch"
+	"github.com/pkg/errors"
 )
 
 var alpineLinuxArchitectureNames = map[int]string{
@@ -88,7 +87,7 @@ func GetArch(distro, arch string) (string, error) {
 
 	archMap, ok := distroArchitecture[distro]
 	if !ok {
-		return "unknown", fmt.Errorf("Architecture map isn't supported: %s", distro)
+		return "unknown", errors.Errorf("Architecture map isn't supported: %s", distro)
 	}
 
 	archID, err := osarch.ArchitectureId(arch)
diff --git a/shared/util.go b/shared/util.go
index 2a100f6..978c073 100644
--- a/shared/util.go
+++ b/shared/util.go
@@ -37,19 +37,19 @@ func Copy(src, dest string) error {
 
 	srcFile, err := os.Open(src)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to open file %q", src)
 	}
 	defer srcFile.Close()
 
 	destFile, err := os.Create(dest)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to create file %q", dest)
 	}
 	defer destFile.Close()
 
 	_, err = io.Copy(destFile, srcFile)
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to copy file")
 	}
 
 	return destFile.Sync()
@@ -74,13 +74,13 @@ func RunCommand(name string, arg ...string) error {
 func RunScript(content string) error {
 	fd, err := unix.MemfdCreate("tmp", 0)
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to create memfd")
 	}
 	defer unix.Close(fd)
 
 	_, err = unix.Write(int(fd), []byte(content))
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to write to memfd")
 	}
 
 	fdPath := fmt.Sprintf("/proc/self/fd/%d", fd)
@@ -159,7 +159,7 @@ func recvGPGKeys(gpgDir string, keyserver string, keys []string) (bool, error) {
 
 		err := cmd.Run()
 		if err != nil {
-			return false, fmt.Errorf("Failed to run: %s: %s", strings.Join(cmd.Args, " "), strings.TrimSpace(buffer.String()))
+			return false, errors.Errorf("Failed to run: %s: %s", strings.Join(cmd.Args, " "), strings.TrimSpace(buffer.String()))
 		}
 	}
 
@@ -202,7 +202,7 @@ func recvGPGKeys(gpgDir string, keyserver string, keys []string) (bool, error) {
 			}
 		}
 
-		return false, fmt.Errorf("Failed to import keys: %s", strings.Join(missingKeys, " "))
+		return false, errors.Errorf("Failed to import keys: %s", strings.Join(missingKeys, " "))
 	}
 
 	return true, nil
@@ -252,7 +252,7 @@ func Pack(filename, compression, path string, args ...string) error {
 	if err != nil {
 		// Clean up incomplete tarball
 		os.Remove(filename)
-		return err
+		return errors.Wrap(err, "Failed to create tarball")
 	}
 
 	return compressTarball(filename, compression)
@@ -262,7 +262,7 @@ func Pack(filename, compression, path string, args ...string) error {
 func PackUpdate(filename, compression, path string, args ...string) error {
 	err := RunCommand("tar", append([]string{"--xattrs", "-uf", filename, "-C", path}, args...)...)
 	if err != nil {
-		return err
+		return errors.Wrap(err, "Failed to update tarball")
 	}
 
 	return compressTarball(filename, compression)
@@ -276,7 +276,10 @@ func compressTarball(filename, compression string) error {
 		defer os.Remove(filename)
 		fallthrough
 	case "bzip2", "xz", "lzip", "lzma", "gzip":
-		return RunCommand(compression, "-f", filename)
+		err := RunCommand(compression, "-f", filename)
+		if err != nil {
+			return errors.Wrapf(err, "Failed to compress tarball %q", filename)
+		}
 	}
 
 	// Do not compress
diff --git a/sources/archlinux-http.go b/sources/archlinux-http.go
index da62843..d911e49 100644
--- a/sources/archlinux-http.go
+++ b/sources/archlinux-http.go
@@ -86,7 +86,7 @@ func (s *archlinux) Run() error {
 	// Unpack
 	err = lxd.Unpack(filepath.Join(fpath, fname), s.rootfsDir, false, false, nil)
 	if err != nil {
-		return err
+		return errors.Wrapf(err, "Failed to unpack file %q", filepath.Join(fpath, fname))
 	}
 
 	// Move everything inside 'root.<architecture>' (which was is the tarball) to its
@@ -131,7 +131,7 @@ func (s *archlinux) getLatestRelease(URL string, arch string) (string, error) {
 	}
 
 	if len(releases) == 0 {
-		return "", errors.Errorf("Failed to determine latest release")
+		return "", errors.New("Failed to determine latest release")
 	}
 
 	// Sort releases in case they're out-of-order
diff --git a/sources/debootstrap.go b/sources/debootstrap.go
index e6f3110..c673131 100644
--- a/sources/debootstrap.go
+++ b/sources/debootstrap.go
@@ -49,7 +49,7 @@ func (s *debootstrap) Run() error {
 	if len(s.definition.Source.Keys) > 0 {
 		keyring, err := shared.CreateGPGKeyring(s.definition.Source.Keyserver, s.definition.Source.Keys)
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to create GPG keyring")
 		}
 		defer os.RemoveAll(path.Dir(keyring))
 
@@ -75,7 +75,7 @@ func (s *debootstrap) Run() error {
 	if !lxd.PathExists(scriptPath) && s.definition.Source.SameAs != "" {
 		err := os.Symlink(s.definition.Source.SameAs, scriptPath)
 		if err != nil {
-			return err
+			return errors.Wrap(err, "Failed to create symlink")
 		}
 
 		defer os.Remove(scriptPath)
diff --git a/sources/funtoo-http.go b/sources/funtoo-http.go
index 0335fc6..38fab70 100644
--- a/sources/funtoo-http.go
+++ b/sources/funtoo-http.go
@@ -69,7 +69,7 @@ func (s *funtoo) Run() error {
 
 	if !s.definition.Source.SkipVerification && url.Scheme != "https" &&
 		len(s.definition.Source.Keys) == 0 {
-		return fmt.Errorf("GPG keys are required if downloading from HTTP")
+		return errors.New("GPG keys are required if downloading from HTTP")
 	}
 
 	var fpath string
@@ -125,7 +125,7 @@ func (s *funtoo) getReleaseDates(URL string) ([]string, error) {
 	}
 
 	if len(dirs) == 0 {
-		return nil, errors.Errorf("Failed to get release dates")
+		return nil, errors.New("Failed to get release dates")
 	}
 
 	// Sort dirs in case they're out-of-order
diff --git a/sources/opensuse-http.go b/sources/opensuse-http.go
index 4abc402..4df5a4e 100644
--- a/sources/opensuse-http.go
+++ b/sources/opensuse-http.go
@@ -111,7 +111,7 @@ func (s *opensuse) verifyTarball(imagePath string, definition shared.Definition)
 	checksumStr := strings.TrimSpace(strings.Split(string(checksum), " ")[0])
 
 	if result != checksumStr {
-		return fmt.Errorf("Hash mismatch for %s: %s != %s", imagePath, result, checksumStr)
+		return errors.Errorf("Hash mismatch for %s: %s != %s", imagePath, result, checksumStr)
 	}
 
 	return nil
diff --git a/sources/openwrt-http.go b/sources/openwrt-http.go
index 5e8e032..0321e69 100644
--- a/sources/openwrt-http.go
+++ b/sources/openwrt-http.go
@@ -140,7 +140,7 @@ func (s *openwrt) Run() error {
 				return errors.Wrap(err, `Failed to verify sha256sums`)
 			}
 			if !valid {
-				return errors.Errorf(`Invalid signature for "sha256sums"`)
+				return errors.New(`Invalid signature for "sha256sums"`)
 			}
 		} else {
 			// Force gpg checks when using http
diff --git a/sources/oraclelinux-http.go b/sources/oraclelinux-http.go
index 284a004..6382a85 100644
--- a/sources/oraclelinux-http.go
+++ b/sources/oraclelinux-http.go
@@ -297,7 +297,7 @@ func (s *oraclelinux) getISO(URL string, architecture string) (string, error) {
 	}
 
 	if len(isos) == 0 {
-		return "", fmt.Errorf("No isos found")
+		return "", errors.New("No isos found")
 	}
 
 	return isos[len(isos)-1], nil
@@ -320,7 +320,7 @@ func (s *oraclelinux) getUpdates(URL string) ([]string, error) {
 	}
 
 	if len(updates) == 0 {
-		return nil, errors.Errorf("No updates found")
+		return nil, errors.New("No updates found")
 	}
 
 	return updates, nil
diff --git a/sources/plamolinux-http.go b/sources/plamolinux-http.go
index 55b7b25..2f77bcf 100644
--- a/sources/plamolinux-http.go
+++ b/sources/plamolinux-http.go
@@ -70,9 +70,9 @@ func (s *plamolinux) Run() error {
 	}
 
 	if len(matches) == 0 {
-		return fmt.Errorf("Couldn't find any matching package")
+		return errors.New("Couldn't find any matching package")
 	} else if len(matches) > 1 {
-		return fmt.Errorf("Found more than one matching package")
+		return errors.New("Found more than one matching package")
 	}
 
 	err = shared.RunCommand("tar", "-pxJf", matches[0], "-C", pkgDir, "sbin/")
@@ -128,7 +128,7 @@ func (s *plamolinux) downloadFiles(def shared.DefinitionImage, URL string, ignor
 	}
 
 	if doc == nil {
-		return "", errors.Errorf("Empty HTML document")
+		return "", errors.New("Empty HTML document")
 	}
 
 	nodes := htmlquery.Find(doc, `//a/@href`)
diff --git a/sources/source.go b/sources/source.go
index 4c3d511..723cae0 100644
--- a/sources/source.go
+++ b/sources/source.go
@@ -1,14 +1,14 @@
 package sources
 
 import (
-	"fmt"
+	"github.com/pkg/errors"
+	"go.uber.org/zap"
 
 	"github.com/lxc/distrobuilder/shared"
-	"go.uber.org/zap"
 )
 
 // ErrUnknownDownloader represents the unknown downloader error
-var ErrUnknownDownloader = fmt.Errorf("Unknown downloader")
+var ErrUnknownDownloader = errors.New("Unknown downloader")
 
 type downloader interface {
 	init(logger *zap.SugaredLogger, definition shared.Definition, rootfsDir string)


Test patch:
diff --git a/shared/definition_test.go b/shared/definition_test.go
index edd5636..fabfebf 100644
--- a/shared/definition_test.go
+++ b/shared/definition_test.go
@@ -477,7 +477,7 @@ func TestDefinitionSetValue(t *testing.T) {
 
 	// Index out of bounds
 	err = d.SetValue("actions.3.trigger", "post-files")
-	require.EqualError(t, err, "Index out of range")
+	require.EqualError(t, err, "Failed to get field by tag: Index out of range")
 
 	// Nonsense
 	err = d.SetValue("image", "[foo: bar]")