{"record":{"id":"510c9951c882efad","repo":"docker/cli","slug":"invalid-credential-spec-cannot-specify-both-s-a","errorCode":null,"errorMessage":"invalid credential spec: cannot specify both %s, and %s","messagePattern":"invalid credential spec: cannot specify both (.+?), and (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/compose/convert/service.go","lineNumber":702,"sourceCode":"\tvar o []string\n\n\tif spec.Config != \"\" {\n\t\to = append(o, `\"Config\"`)\n\t}\n\tif spec.File != \"\" {\n\t\to = append(o, `\"File\"`)\n\t}\n\tif spec.Registry != \"\" {\n\t\to = append(o, `\"Registry\"`)\n\t}\n\tl := len(o)\n\tswitch {\n\tcase l == 0:\n\t\treturn nil, nil\n\tcase l == 2:\n\t\treturn nil, fmt.Errorf(\"invalid credential spec: cannot specify both %s and %s\", o[0], o[1])\n\tcase l > 2:\n\t\treturn nil, fmt.Errorf(\"invalid credential spec: cannot specify both %s, and %s\", strings.Join(o[:l-1], \", \"), o[l-1])\n\t}\n\tswarmCredSpec := swarm.CredentialSpec(spec)\n\t// if we're using a swarm Config for the credential spec, over-write it\n\t// here with the config ID\n\tif swarmCredSpec.Config != \"\" {\n\t\tfor _, config := range refs {\n\t\t\tif swarmCredSpec.Config == config.ConfigName {\n\t\t\t\tswarmCredSpec.Config = config.ConfigID\n\t\t\t\treturn &swarmCredSpec, nil\n\t\t\t}\n\t\t}\n\t\t// if none of the configs match, try namespacing\n\t\tfor _, config := range refs {\n\t\t\tif namespace.Scope(swarmCredSpec.Config) == config.ConfigName {\n\t\t\t\tswarmCredSpec.Config = config.ConfigID\n\t\t\t\treturn &swarmCredSpec, nil\n\t\t\t}\n\t\t}","sourceCodeStart":684,"sourceCodeEnd":720,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cli/compose/convert/service.go#L684-L720","documentation":"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.","triggerScenarios":"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.","commonSituations":"Iterative edits that never removed prior credential-spec keys; merging compose files that each contributed a different source.","solutions":["Reduce credential_spec to a single one of config/file/registry.","Delete the extra two keys and redeploy."],"exampleFix":"// before\ncredential_spec:\n  config: cred-conf\n  file: ./gmsa.json\n  registry: myreg/gmsa\n// after\ncredential_spec:\n  config: cred-conf","handlingStrategy":"validation","validationCode":"// Same check as 450 covers the >2 case (count keys set; reject if > 1).\nfunc validateCredentialSpecKeys(cfg *composetypes.Config) error {\n    for _, svc := range cfg.Services {\n        cs := svc.CredentialSpec\n        n := 0\n        for _, v := range []string{cs.Config, cs.File, cs.Registry} {\n            if v != \"\" { n++ }\n        }\n        if n > 1 {\n            return fmt.Errorf(\"invalid credential spec: at most one of Config/File/Registry allowed (got %d)\", n)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep credential_spec to a single source key.","Avoid merging multiple compose files that each set a different credential source.","Lint credential_spec key counts in CI."],"tags":["compose","convert","credential-spec","swarm","windows","gmsa"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}