docker/cli · error

invalid restart policy: unknown policy

Error message

invalid restart policy: unknown policy '%s' (must be one of '%s', '%s', '%s', or '%s')

What it means

Returned by the restart-policy converter's default branch when policy.Name does not match any of the supported Swarm conditions (service.go:508-525). Swarm only accepts 'no'/'', 'always', 'unless-stopped', and 'on-failure'; any other string is rejected with a message listing the valid values.

Solutions

  1. Set deploy.restart_policy.condition to one of: 'no', 'always', 'unless-stopped', 'on-failure'.
  2. Remove the restart_policy block to use the default (disabled) behavior.
  3. Double-check spelling against the four values listed in the error message.

Example fix

// before
deploy:
  restart_policy:
    condition: whenever
// after
deploy:
  restart_policy:
    condition: on-failure
    max_attempts: 3
Defensive patterns

Strategy: validation

Validate before calling

var validRestartConditions = map[string]bool{
    "": true, "no": true, "always": true, "on-failure": true, "unless-stopped": true,
}
func validateRestartPolicy(cfg *composetypes.Config) error {
    for _, svc := range cfg.Services {
        if n := svc.Deploy.RestartPolicy.Name; n != "" && !validRestartConditions[n] {
            return fmt.Errorf("invalid restart policy: unknown policy %q", n)
        }
    }
    return nil
}

Prevention

When it happens

Trigger: Setting deploy.restart_policy.condition to a value other than the four enumerated constants (e.g. 'whenever', 'never', 'restart'). Reached at service.go:521 default case.

Common situations: Using container-engine restart-policy names that aren't valid Swarm conditions; typos like 'allways'; copy-pasting a policy from a non-Swarm compose example.

Related errors


AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07). Data as JSON: /api/errors/cc212b7a5c3e9269. Report an issue: GitHub.

Appendix: source

Thrown at cli/compose/convert/service.go:522

		p := uint64(i)
		return &p
	}

	switch policy.Name {
	case container.RestartPolicyDisabled, "":
		return nil, nil
	case container.RestartPolicyAlways, container.RestartPolicyUnlessStopped:
		return &swarm.RestartPolicy{
			Condition:   swarm.RestartPolicyConditionAny,
			MaxAttempts: uint64Ptr(policy.MaximumRetryCount),
		}, nil
	case container.RestartPolicyOnFailure:
		return &swarm.RestartPolicy{
			Condition:   swarm.RestartPolicyConditionOnFailure,
			MaxAttempts: uint64Ptr(policy.MaximumRetryCount),
		}, nil
	default:
		return nil, fmt.Errorf("invalid restart policy: unknown policy '%s' (must be one of '%s', '%s', '%s', or '%s')",
			policy.Name, container.RestartPolicyDisabled, container.RestartPolicyAlways, container.RestartPolicyOnFailure, container.RestartPolicyUnlessStopped,
		)
	}
}

func convertUpdateConfig(source *composetypes.UpdateConfig) *swarm.UpdateConfig {
	if source == nil {
		return nil
	}
	parallel := uint64(1)
	if source.Parallelism != nil {
		parallel = *source.Parallelism
	}
	return &swarm.UpdateConfig{
		Parallelism:     parallel,
		Delay:           time.Duration(source.Delay),
		FailureAction:   swarm.FailureAction(source.FailureAction),
		Monitor:         time.Duration(source.Monitor),

View on GitHub (pinned to 4f84911bfe)