{"record":{"id":"dab5c59d5b0ba418","repo":"docker/cli","slug":"failed-to-update-config-s-w","errorCode":null,"errorMessage":"failed to update config %s: %w","messagePattern":"failed to update config (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/command/stack/deploy_composefile.go","lineNumber":154,"sourceCode":"\t\t}\n\t}\n\treturn nil\n}\n\nfunc createConfigs(ctx context.Context, dockerCLI command.Cli, configs []swarm.ConfigSpec) error {\n\tapiClient := dockerCLI.Client()\n\n\tfor _, configSpec := range configs {\n\t\tres, err := apiClient.ConfigInspect(ctx, configSpec.Name, client.ConfigInspectOptions{})\n\t\tswitch {\n\t\tcase err == nil:\n\t\t\t// config already exists, then we update that\n\t\t\t_, err := apiClient.ConfigUpdate(ctx, res.Config.ID, client.ConfigUpdateOptions{\n\t\t\t\tVersion: res.Config.Meta.Version,\n\t\t\t\tSpec:    configSpec,\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to update config %s: %w\", configSpec.Name, err)\n\t\t\t}\n\t\tcase errdefs.IsNotFound(err):\n\t\t\t// config does not exist, then we create a new one.\n\t\t\t_, _ = fmt.Fprintln(dockerCLI.Out(), \"Creating config\", configSpec.Name)\n\t\t\t_, err := apiClient.ConfigCreate(ctx, client.ConfigCreateOptions{\n\t\t\t\tSpec: configSpec,\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to create config %s: %w\", configSpec.Name, err)\n\t\t\t}\n\t\tdefault:\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc createNetworks(ctx context.Context, dockerCLI command.Cli, namespace convert.Namespace, networks map[string]client.NetworkCreateOptions) error {","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cli/command/stack/deploy_composefile.go#L136-L172","documentation":"Raised by createConfigs when a swarm config already exists (found via ConfigInspect) but the subsequent ConfigUpdate API call fails. The wrapped %w error carries the underlying daemon error. Configs are the mutable-file equivalent of secrets and follow the same inspect-then-update lifecycle during redeploy.","triggerScenarios":"Redeploying a stack where a config in compose.yml was changed, causing ConfigUpdate at deploy_composefile.go:149 to fail. Triggers on version conflicts, immutable-field changes, or concurrent modification between the Inspect and Update.","commonSituations":"Concurrent stack deploys racing on the same config; manager node unhealthy; changing a field the daemon treats as immutable on update; config removed out-of-band mid-deploy.","solutions":["Read the wrapped error for the daemon-specific reason.","Retry the deploy to clear transient version conflicts.","Remove and recreate the config: `docker config rm <name>` then redeploy.","Serialize concurrent deploys targeting the same stack's configs."],"exampleFix":"// before: redeploy fails on version conflict\n// after: remove stale config and redeploy\ndocker config rm mystack_myconfig\ndocker stack deploy -c compose.yml mystack","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Retry on transient config update failures (e.g. version conflict)\nfor attempt := 0; attempt < 3; attempt++ {\n    err := stackDeploy(ctx, cli, opts, cfg)\n    if err == nil { return nil }\n    if !strings.Contains(err.Error(), \"failed to update config\") {\n        return err\n    }\n}\nreturn errors.New(\"config update failed after retries\")","preventionTips":["Serialize concurrent deploys touching the same configs.","Treat version-conflict wrapped errors as retriable.","For breaking changes, remove and recreate the config."],"tags":["docker","stack","config","swarm","update"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}