hashicorp/nomad · error

image_path is not in the allowed paths

Error message

image_path is not in the allowed paths

What it means

The QEMU driver validates, at task start, that the VM image path (image_path) is either inside one of the client's configured 'image_paths' allowlist directories or inside the task's allocation directory. If isAllowedImagePath() rejects the path, StartTask refuses to launch the VM. This is a security guard against arbitrary file access by task authors, since QEMU would otherwise run with whatever disk image the task specifies.

Source

Thrown at drivers/qemu/driver.go:489

	handle.Config = cfg

	if err := validateEmulator(driverConfig.Emulator, d.config.EmulatorsAllowList); err != nil {
		return nil, nil, err
	}

	if err := validateArgs(d.config.ArgsAllowList, driverConfig.Args); err != nil {
		return nil, nil, err
	}

	// Get the image source
	vmPath := driverConfig.ImagePath
	if vmPath == "" {
		return nil, nil, fmt.Errorf("image_path must be set")
	}
	vmID := filepath.Base(vmPath)

	if !isAllowedImagePath(d.config.ImagePaths, cfg.AllocDir, vmPath) {
		return nil, nil, fmt.Errorf("image_path is not in the allowed paths")
	}

	// Parse configuration arguments
	// Create the base arguments
	emulator := "x86_64"
	if driverConfig.Emulator != "" {
		// COMPAT: TrimPrefix to support full emulator name
		// which was required in 1.11.1.
		emulator = strings.TrimPrefix(driverConfig.Emulator, "qemu-system-")

	}
	accelerator := "tcg"
	if driverConfig.Accelerator != "" {
		accelerator = driverConfig.Accelerator
	}
	machineType := "pc"
	if driverConfig.MachineType != "" {
		machineType = driverConfig.MachineType

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Add the directory containing the VM image to the client QEMU driver config: plugin "qemu" { driver "qemu" { image_paths = ["/srv/images"] } } and restart the Nomad client.
  2. Place the image inside the task's allocation directory (e.g. download it with an artifact block) which is always allowed.
  3. Verify the image_path in the task's driver config exactly matches a real file under one of the allowed roots (check for typos and symlinks).

Example fix

// task config: before
image_path = "/home/ops/alpine.qcow2"
// after (client hcl: plugin "qemu" { config { image_paths = ["/srv/images"] } })
image_path = "/srv/images/alpine.qcow2"
Defensive patterns

Strategy: validation

Validate before calling

// before submitting, confirm image lives under an allowed root
const allowedRoots = ["/srv/images"]; // must match client config image_paths
function isAllowedImagePath(root, allocDir, p) {
  const abs = require("path").resolve(p);
  return [allocDir, ...root].some
    ? [allocDir, ...allowedRoots].some((r) => abs.startsWith(require("path").resolve(r) + require("path").sep))
    : false;
}

Type guard

function hasAllowedImagePath(cfg) {
  return typeof cfg.image_path === "string" && cfg.image_path.length > 0 &&
    allowedRoots.some((r) => require("path").resolve(cfg.image_path).startsWith(require("path").resolve(r) + require("path").sep));
}

Try / catch

try {
  await nomad.jobs.startTask(cfg);
} catch (e) {
  if (String(e.message).includes("image_path is not in the allowed paths")) {
    console.error(`Move ${cfg.image_path} under an image_paths root or add its dir to client config`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling tasks.start (QEMU driver) with driver config image_path pointing to a file outside config.image_paths allowlist and outside the task's alloc dir; empty or mis-scoped image_paths in the client 'plugin.qemu.driver.image_paths' config; using a relative or symlinked path that resolves outside allowed roots.

Common situations: Operator forgets to add the image directory to image_paths in the Nomad client config; dev setups using images in /home or /tmp while allowlist points elsewhere; images mounted at a different path on the client node than in the allowlist; path typo or symlink chain escaping the allowlist.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/0659df482d117b7e. Report an issue: GitHub.