nektos/act · error

invalid storage option

Error message

invalid storage option

What it means

parseStorageOpts splits each --storage-opt entry on the first '=' using strings.Cut; an entry without an '=' character cannot form a key/value pair and is rejected outright with 'invalid storage option'. This mirrors the Docker CLI's own validation, so anything docker run would reject also fails at act's parse layer before the container is created.

Source

Thrown at pkg/container/docker_cli.go:994

	for _, opt := range securityOpts {
		if opt == "systempaths=unconfined" {
			maskedPaths = []string{}
			readonlyPaths = []string{}
		} else {
			filtered = append(filtered, opt)
		}
	}

	return filtered, maskedPaths, readonlyPaths
}

// parses storage options per container into a map
func parseStorageOpts(storageOpts []string) (map[string]string, error) {
	m := make(map[string]string)
	for _, option := range storageOpts {
		k, v, ok := strings.Cut(option, "=")
		if !ok {
			return nil, errors.New("invalid storage option")
		}
		m[k] = v
	}
	return m, nil
}

// parseDevice parses a device mapping string to a container.DeviceMapping struct
func parseDevice(device, serverOS string) (container.DeviceMapping, error) {
	switch serverOS {
	case "linux":
		return parseLinuxDevice(device)
	case "windows":
		// Windows doesn't support mapping, so passing the given value as-is.
		return container.DeviceMapping{PathOnHost: device}, nil
	default:
		return container.DeviceMapping{}, fmt.Errorf("unknown server OS: %s", serverOS)
	}
}

View on GitHub (pinned to 4f41128141)

Solutions

  1. Rewrite the option in key=value form: '--storage-opt size=10G'.
  2. Verify YAML quoting of the options line so '=' survives parsing (quote the whole string in single quotes).
  3. Confirm the key is valid for your storage driver (size only works on overlay2 with pquota, btrfs, zfs, devicethrow); an invalid key with correct syntax will instead be rejected by the daemon.
  4. Remove stray/duplicate --storage-opt flags that parse to empty strings.

Example fix

# before
container:
  image: node:20
  options: --storage-opt size

# after
container:
  image: node:20
  options: --storage-opt size=10G
Defensive patterns

Strategy: validation

Validate before calling

package main

import (
	"fmt"
	"strings"
)

func validateStorageOpts(options string) error {
	for i, f := range strings.Fields(options) {
		if f == "--storage-opt" {
			if i+1 >= len(strings.Fields(options)) || !strings.Contains(strings.Fields(options)[i+1], "=") {
				return fmt.Errorf("--storage-opt requires key=value (got no '=' in next token)")
			}
		}
		if v, ok := strings.CutPrefix(f, "--storage-opt="); ok && !strings.Contains(v, "=") {
			return fmt.Errorf("--storage-opt=%q lacks '='", v)
		}
	}
	return nil
}

Try / catch

if err := exec.NewContainerExecutor(...)(ctx); err != nil {
    if strings.Contains(err.Error(), "invalid storage option") {
        return fmt.Errorf("fix container options: each --storage-opt must be key=value: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: A container options string containing a bare flag-style storage option, e.g. 'options: --storage-opt size' (missing '=10G'), or a trailing empty entry like '--storage-opt ' after shell-style splitting. Any element of the parsed storageOpts slice that contains no '=' character.

Common situations: Typing '--storage-opt size' instead of '--storage-opt size=10G' on overlay2/btrfs/zfs drivers; copy-pasting options where the value was dropped; quoting mistakes in YAML that strip the '=value' part during shell-like splitting of the options line.

Related errors


AI-assisted analysis of nektos/act@4f41128141 (2026-08-15). Data as JSON: /api/errors/6bf48bd174de64a8. Report an issue: GitHub.