containerd/containerd · error

index out of bounds: %d, has %d active mounts

Error message

index out of bounds: %d, has %d active mounts

What it means

The mount manager expands Go-template placeholders in mount Source/Target/Options (e.g. {{ source 0 }}, {{ mount 1 }}) against the list of ActiveMounts. The 'source' template function returns this error when the template's index is negative or >= the number of active mounts, guarding against a slice panic.

Source

Thrown at core/mount/manager/format.go:80

		}
	}
	if o != nil {
		m.Options = o
	}
	return m, nil
}

func formatString(s string) func([]mount.ActiveMount) (string, error) {
	if !strings.Contains(s, formatCheck) {
		return nil
	}

	return func(a []mount.ActiveMount) (string, error) {
		// TODO: The formatting is very easy, don't use template
		fm := template.FuncMap{
			"source": func(i int) (string, error) {
				if i < 0 || i >= len(a) {
					return "", fmt.Errorf("index out of bounds: %d, has %d active mounts", i, len(a))
				}
				return a[i].Source, nil
			},
			"target": func(i int) (string, error) {
				if i < 0 || i >= len(a) {
					return "", fmt.Errorf("index out of bounds: %d, has %d active mounts", i, len(a))
				}
				return a[i].Target, nil
			},
			"mount": func(i int) (string, error) {
				if i < 0 || i >= len(a) {
					return "", fmt.Errorf("index out of bounds: %d, has %d active mounts", i, len(a))
				}
				return a[i].MountPoint, nil
			},
			"overlay": func(start, end int) (string, error) {
				var dirs []string
				if start > end {

View on GitHub (pinned to 4246446a2b)

Solutions

  1. Reduce the template index in the mount Source (e.g. {{ source 0 }}) to be within the actual number of active mounts.
  2. Log len(activeMounts) at the call site and compare against the index used in the template to find the mismatch.
  3. Fix the snapshotter/packager that emitted the mount spec so its template matches the layer count it produces.
  4. Validate mount templates at snapshot-preparation time rather than failing at mount time.

Example fix

// before
Options: []string{"upperdir={{ mount 3 }}/fs", "workdir={{ mount 3 }}/work"}
// after (only 2 active mounts exist)
Options: []string{"upperdir={{ mount 1 }}/fs", "workdir={{ mount 1 }}/work"}
Defensive patterns

Strategy: validation

Validate before calling

// before mounting, ensure template indices fit the active mount count
for _, opt := range mount.Options {
    for _, m := range indexRegexp.FindAllStringSubmatch(opt, -1) {
        i, _ := strconv.Atoi(m[1])
        if i < 0 || i >= len(activeMounts) {
            return fmt.Errorf("template index %d out of range for %d mounts", i, len(activeMounts))
        }
    }
}

Try / catch

_, err := mgr.Mount(ctx, mounts...)
if err != nil {
    var ierr *fmt.Errorf
    if strings.Contains(err.Error(), "index out of bounds") {
        return fmt.Errorf("mount template references missing snapshot layer: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: A mount spec whose Source contains a template like {{ source 5 }} but Transform/Mount is invoked with fewer than 6 ActiveMount entries (or a negative index, e.g. computed from a bad snapshot ID).

Common situations: Overlay/snapshotter configurations where the template index assumes more parent layers than actually exist (pruned or flattened snapshots); mounts applied to the wrong snapshotter with a different layer count; off-by-one in generated mount options.

Related errors


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