docker/cli · error

failed to create secret

Error message

failed to create secret %s: %w

What it means

Raised by createSecrets when a secret does not exist yet (NotFound after SecretInspect) and the SecretCreate API call then fails. The wrapped %w carries the underlying error (e.g. secret name conflict surfaced at create, data too large, or driver error).

Solutions

  1. Check the wrapped error for the daemon reason (size limit, invalid name).
  2. Ensure secret names are lowercase, match [a-zA-Z0-9_.-], and are <= 64 chars (compose prefixes them with the stack name).
  3. Verify the secret data is <= 500KB.
  4. Retry; if a concurrent deploy won the race, the next deploy will treat it as an update.

Example fix

// before: secret name too long after stack prefix
secrets:
  my_incredibly_long_secret_name_exceeding_limits:
    file: ./secret.txt
// after: shorten the name
secrets:
  my_secret:
    file: ./secret.txt
Defensive patterns

Strategy: validation

Validate before calling

// Validate secret names and sizes before deploy
const maxSecretBytes = 500 * 1024
var validName = regexp.MustCompile(`^[a-zA-Z0-9](?:[a-zA-Z0-9_.-]{0,63})$`)

func validateSecret(name, data string, stackNS string) error {
    full := stackNS + "_" + name
    if !validName.MatchString(full) || len(full) > 64 {
        return fmt.Errorf("invalid secret name %q", full)
    }
    if len(data) > maxSecretBytes {
        return fmt.Errorf("secret %q too large: %d bytes", name, len(data))
    }
    return nil
}

Prevention

When it happens

Trigger: First-time deploy of a stack with secrets defined in compose.yml, where SecretCreate at deploy_composefile.go:128 returns an error. Also when a secret was removed between the Inspect (NotFound) and Create, causing a name collision.

Common situations: Secret payload exceeding the 500KB limit; invalid secret name (e.g. uppercase or illegal chars); concurrent deploy creating the same secret name; external secret driver misconfigured on the Swarm.

Related errors


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

Appendix: source

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

		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 {
	apiClient := dockerCLI.Client()

	for _, configSpec := range configs {
		res, err := apiClient.ConfigInspect(ctx, configSpec.Name, client.ConfigInspectOptions{})
		switch {
		case err == nil:
			// config already exists, then we update that
			_, err := apiClient.ConfigUpdate(ctx, res.Config.ID, client.ConfigUpdateOptions{
				Version: res.Config.Meta.Version,

View on GitHub (pinned to 4f84911bfe)