docker/cli · error

invalid credential spec: cannot specify both

Error message

invalid credential spec: cannot specify both %s, and %s

What it means

Returned by convertCredentialSpec when all three of Config/File/Registry are set (service.go:701-702). The message joins the first two fields and the last into a single 'cannot specify both X, and Y' string. As with error 450, only one source may be provided.

Solutions

  1. Reduce credential_spec to a single one of config/file/registry.
  2. Delete the extra two keys and redeploy.

Example fix

// before
credential_spec:
  config: cred-conf
  file: ./gmsa.json
  registry: myreg/gmsa
// after
credential_spec:
  config: cred-conf
Defensive patterns

Strategy: validation

Validate before calling

// Same check as 450 covers the >2 case (count keys set; reject if > 1).
func validateCredentialSpecKeys(cfg *composetypes.Config) error {
    for _, svc := range cfg.Services {
        cs := svc.CredentialSpec
        n := 0
        for _, v := range []string{cs.Config, cs.File, cs.Registry} {
            if v != "" { n++ }
        }
        if n > 1 {
            return fmt.Errorf("invalid credential spec: at most one of Config/File/Registry allowed (got %d)", n)
        }
    }
    return nil
}

Prevention

When it happens

Trigger: A service's credential_spec sets config, file, AND registry simultaneously. The slice `o` has length 3 (>2) and the switch at service.go:701 fires.

Common situations: Iterative edits that never removed prior credential-spec keys; merging compose files that each contributed a different source.

Related errors


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

Appendix: source

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

	var o []string

	if spec.Config != "" {
		o = append(o, `"Config"`)
	}
	if spec.File != "" {
		o = append(o, `"File"`)
	}
	if spec.Registry != "" {
		o = append(o, `"Registry"`)
	}
	l := len(o)
	switch {
	case l == 0:
		return nil, nil
	case l == 2:
		return nil, fmt.Errorf("invalid credential spec: cannot specify both %s and %s", o[0], o[1])
	case l > 2:
		return nil, fmt.Errorf("invalid credential spec: cannot specify both %s, and %s", strings.Join(o[:l-1], ", "), o[l-1])
	}
	swarmCredSpec := swarm.CredentialSpec(spec)
	// if we're using a swarm Config for the credential spec, over-write it
	// here with the config ID
	if swarmCredSpec.Config != "" {
		for _, config := range refs {
			if swarmCredSpec.Config == config.ConfigName {
				swarmCredSpec.Config = config.ConfigID
				return &swarmCredSpec, nil
			}
		}
		// if none of the configs match, try namespacing
		for _, config := range refs {
			if namespace.Scope(swarmCredSpec.Config) == config.ConfigName {
				swarmCredSpec.Config = config.ConfigID
				return &swarmCredSpec, nil
			}
		}

View on GitHub (pinned to 4f84911bfe)