containerd/containerd · error

failed to find UtilityVM directory in base layer %q: %w

Error message

failed to find UtilityVM directory in base layer %q: %w

What it means

createUVMScratchLayer builds a scratch layer for a Utility VM from a base Windows layer. It requires the base (last parent) layer to contain a UtilityVM directory; if os.Stat finds it missing, this error reports which base layer path lacks it. Utility VM images are only produced for Windows process/hypervisor-isolated base images that include the UVM components.

Source

Thrown at plugins/snapshots/windows/common.go:212

}

// Close closes the snapshotter
func (w *windowsBaseSnapshotter) Close() error {
	return w.ms.Close()
}

// This handles creating the UVMs scratch layer.
func (w *windowsBaseSnapshotter) createUVMScratchLayer(ctx context.Context, snDir string, parentLayers []string) error {
	parentLen := len(parentLayers)
	if parentLen == 0 {
		return errors.New("no parent layers present")
	}
	baseLayer := parentLayers[parentLen-1]

	// Make sure base layer has a UtilityVM folder.
	uvmPath := filepath.Join(baseLayer, "UtilityVM")
	if _, err := os.Stat(uvmPath); os.IsNotExist(err) {
		return fmt.Errorf("failed to find UtilityVM directory in base layer %q: %w", baseLayer, err)
	}

	templateDiffDisk := filepath.Join(uvmPath, "SystemTemplate.vhdx")

	// Check if SystemTemplate disk doesn't exist for some reason (this should be made during the unpacking
	// of the base layer).
	if _, err := os.Stat(templateDiffDisk); os.IsNotExist(err) {
		return fmt.Errorf("%q does not exist in Utility VM image", templateDiffDisk)
	}

	// Move the sandbox.vhdx into a nested vm folder to avoid clashing with a containers sandbox.vhdx.
	vmScratchDir := filepath.Join(snDir, "vm")
	if err := os.MkdirAll(vmScratchDir, 0777); err != nil {
		return fmt.Errorf("failed to make `vm` directory for vm's scratch space: %w", err)
	}

	return copyScratchDisk(templateDiffDisk, filepath.Join(vmScratchDir, "sandbox.vhdx"))
}

View on GitHub (pinned to 4246446a2b)

Solutions

  1. Verify the base image is a Windows base layer that ships a UtilityVM directory (check the layer on disk)
  2. Re-pull/re-extract the base image — a corrupted or partial unpack may have dropped UtilityVM
  3. Ensure you are not mistakenly passing a non-base (child) layer as the last parent
  4. Use an image built for the matching Windows build/hypervisor isolation scenario
Defensive patterns

Strategy: validation

Validate before calling

// Before invoking the UVM scratch path, verify the base layer
uvmDir := filepath.Join(baseLayerPath, "UtilityVM")
if fi, err := os.Stat(uvmDir); err != nil || !fi.IsDir() {
    return fmt.Errorf("base layer %s lacks UtilityVM dir", baseLayerPath)
}

Try / catch

if err != nil && strings.Contains(err.Error(), "failed to find UtilityVM directory") {
    return fmt.Errorf("image is not a Windows UVM-capable base layer: %w", err)
}

Prevention

When it happens

Trigger: Calling createUVMScratchLayer (via the anonymous snapshotter path) with parentLayers whose final entry has no UtilityVM subdirectory — i.e. the base image was not a proper Windows base layer with UVM support.

Common situations: Using a nanoserver/servercore variant or custom image without UtilityVM contents as the base for a hyper-v snapshotter; layer unpacking partially failed so UtilityVM was never written; pointing the snapshotter at the wrong parent layer list.

Related errors


AI-assisted analysis of containerd/containerd@4246446a2b (2026-09-02). Data as JSON: /api/errors/9f27e189d94a08f6. Report an issue: GitHub.