docker/cli · error
invalid option for flag --resolve-image
Error message
invalid option %s for flag --resolve-image
What it means
Raised by runDeploy when the --resolve-image flag value is not one of the three allowed constants: always, changed, or never. This flag controls whether/how the registry is queried to resolve image digests during stack deploy.
Solutions
- Use exactly one of: --resolve-image=always, --resolve-image=changed, or --resolve-image=never.
- If sourcing the value from a variable, validate it against the allowed set before invoking deploy.
- Check the Docker CLI version docs to confirm the option set hasn't changed.
Example fix
// before docker stack deploy --resolve-image allways mystack -c compose.yml // after docker stack deploy --resolve-image always mystack -c compose.yml
Defensive patterns
Strategy: validation
Validate before calling
var validResolveImage = map[string]struct{}{"always": {}, "changed": {}, "never": {}}
func resolveImageOpt(v string) error {
if _, ok := validResolveImage[v]; !ok {
return fmt.Errorf("invalid --resolve-image value %q; want always|changed|never", v)
}
return nil
} Type guard
type ResolveImage string
const (
ResolveAlways ResolveImage = "always"
ResolveChanged ResolveImage = "changed"
ResolveNever ResolveImage = "never"
)
func (r ResolveImage) Valid() bool {
switch r {
case ResolveAlways, ResolveChanged, ResolveNever:
return true
}
return false
} Prevention
- Type the option as a Go enum/const so invalid values can't be constructed.
- Validate config-sourced values against the allowed set before invoking deploy.
- Document the three options wherever the flag is exposed.
When it happens
Trigger: Running `docker stack deploy --resolve-image <value>` where <value> is anything other than 'always', 'changed', or 'never'. The switch at deploy.go:82 falls through to the default branch. This typically happens only with typos or direct API/library calls since cobra flag validation usually catches it earlier.
Common situations: Typo like 'allways', 'chagned', 'true', or 'on'; passing a value sourced from a config/env var without validation; older docs referencing a removed/renamed option.
Related errors
- this node is not a swarm manager. Use "docker swarm init"…
- specify a Compose file (with --compose-file)
- failed to update service
- failed to create service
- %s: %w
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/093efde16d2b9771.
Report an issue: GitHub.
Appendix: source
Thrown at cli/command/stack/deploy.go:86
return cmd
}
// Resolve image constants
const (
resolveImageAlways = "always"
resolveImageChanged = "changed"
resolveImageNever = "never"
)
const defaultNetworkDriver = "overlay"
// runDeploy is the swarm implementation of docker stack deploy
func runDeploy(ctx context.Context, dockerCLI command.Cli, flags *pflag.FlagSet, opts *deployOptions, cfg *composetypes.Config) error {
switch opts.resolveImage {
case resolveImageAlways, resolveImageChanged, resolveImageNever:
// valid options.
default:
return fmt.Errorf("invalid option %s for flag --resolve-image", opts.resolveImage)
}
if opts.detach && !flags.Changed("detach") {
_, _ = fmt.Fprintln(dockerCLI.Err(), "Since --detach=false was not specified, tasks will be created in the background.\n"+
"In a future release, --detach=false will become the default.")
}
return deployCompose(ctx, dockerCLI, opts, cfg)
}
// checkDaemonIsSwarmManager does an Info API call to verify that the daemon is
// a swarm manager. This is necessary because we must create networks before we
// create services, but the API call for creating a network does not return a
// proper status code when it can't create a network in the "global" scope.
func checkDaemonIsSwarmManager(ctx context.Context, dockerCli command.Cli) error {
res, err := dockerCli.Client().Info(ctx, client.InfoOptions{})
if err != nil {
return errView on GitHub (pinned to 4f84911bfe)