docker/cli · error

failed to update secret

Error message

failed to update secret %s: %w

What it means

Raised by createSecrets when a swarm secret already exists (found via SecretInspect) but the subsequent SecretUpdate API call fails. The wrapped %w error carries the underlying daemon error (e.g. version conflict, immutable field change, permission).

Solutions

  1. Inspect the wrapped error message for the daemon's specific reason (e.g. 'update out of sequence').
  2. Retry the deploy; transient version conflicts often resolve on the next attempt.
  3. If the secret is truly malformed, remove it (`docker secret rm <name>`) and redeploy so it is recreated.
  4. Ensure no concurrent deploys are modifying the same stack's secrets.

Example fix

// before: concurrent deploys cause version conflict
// after: serialize deploys or retry
for i in 1 2 3; do docker stack deploy -c compose.yml mystack && break || sleep 2; done
Defensive patterns

Strategy: retry

Try / catch

// Retry on transient secret update failures (e.g. version conflict)
var lastErr error
for attempt := 0; attempt < 3; attempt++ {
    if err := stackDeploy(ctx, cli, opts, cfg); err == nil {
        return nil
    } else if strings.Contains(err.Error(), "failed to update secret") {
        lastErr = err
        continue // likely a transient version conflict
    } else {
        return err
    }
}
return lastErr

Prevention

When it happens

Trigger: Redeploying a stack where a secret in compose.yml was modified, causing SecretUpdate at deploy_composefile.go:118 to return an error. Common when changing a field that the daemon rejects on update, or when the secret's version/meta is stale due to concurrent modification.

Common situations: Concurrent stack deploys racing on the same secret; changing an immutable attribute (e.g. driver labels) of an existing secret; manager node temporarily unhealthy; removing a secret out-of-band between the Inspect and Update calls.

Related errors


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

Appendix: source

Thrown at cli/command/stack/deploy_composefile.go:123

		}
	}
	return nil
}

func createSecrets(ctx context.Context, dockerCLI command.Cli, secrets []swarm.SecretSpec) error {
	apiClient := dockerCLI.Client()

	for _, secretSpec := range secrets {
		res, err := apiClient.SecretInspect(ctx, secretSpec.Name, client.SecretInspectOptions{})
		switch {
		case err == nil:
			// secret already exists, then we update that
			_, err := apiClient.SecretUpdate(ctx, res.Secret.ID, client.SecretUpdateOptions{
				Version: res.Secret.Meta.Version,
				Spec:    secretSpec,
			})
			if err != nil {
				return fmt.Errorf("failed to update secret %s: %w", secretSpec.Name, err)
			}
		case errdefs.IsNotFound(err):
			// secret does not exist, then we create a new one.
			_, _ = fmt.Fprintln(dockerCLI.Out(), "Creating secret", secretSpec.Name)
			_, err := apiClient.SecretCreate(ctx, client.SecretCreateOptions{
				Spec: secretSpec,
			})
			if err != nil {
				return fmt.Errorf("failed to create secret %s: %w", secretSpec.Name, err)
			}
		default:
			return err
		}
	}
	return nil
}

func createConfigs(ctx context.Context, dockerCLI command.Cli, configs []swarm.ConfigSpec) error {

View on GitHub (pinned to 4f84911bfe)