{"record":{"id":"52e86367b4aecb15","repo":"docker/cli","slug":"undefined-secret-q","errorCode":null,"errorMessage":"undefined secret %q","messagePattern":"undefined secret %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/compose/convert/service.go","lineNumber":255,"sourceCode":"\n\tsort.Slice(nets, func(i, j int) bool {\n\t\treturn nets[i].Target < nets[j].Target\n\t})\n\treturn nets, nil\n}\n\n// TODO: fix secrets API so that SecretAPIClient is not required here\nfunc convertServiceSecrets(\n\tctx context.Context,\n\tapiClient client.SecretAPIClient,\n\tnamespace Namespace,\n\tsecrets []composetypes.ServiceSecretConfig,\n\tsecretSpecs map[string]composetypes.SecretConfig,\n) ([]*swarm.SecretReference, error) {\n\tlookup := func(key string) (composetypes.FileObjectConfig, error) {\n\t\tsecretSpec, exists := secretSpecs[key]\n\t\tif !exists {\n\t\t\treturn composetypes.FileObjectConfig{}, fmt.Errorf(\"undefined secret %q\", key)\n\t\t}\n\t\treturn composetypes.FileObjectConfig(secretSpec), nil\n\t}\n\n\trefs := make([]*swarm.SecretReference, 0, len(secrets))\n\tfor _, secret := range secrets {\n\t\tobj, err := convertFileObject(namespace, composetypes.FileReferenceConfig(secret), lookup)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tfile := swarm.SecretReferenceFileTarget(obj.File)\n\t\trefs = append(refs, &swarm.SecretReference{\n\t\t\tFile:       &file,\n\t\t\tSecretName: obj.Name,\n\t\t})\n\t}\n","sourceCodeStart":237,"sourceCodeEnd":273,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cli/compose/convert/service.go#L237-L273","documentation":"Returned by the secret lookup closure inside convertServiceSecrets when a secret referenced by a service is not present in the top-level secretSpecs map (service.go:253-256). The named secret must be declared before it can be attached.","triggerScenarios":"A service's `secrets:` list names a secret that does not appear under the top-level `secrets:` key. The lookup at service.go:254 returns false and the error fires.","commonSituations":"Secret added to a service but not declared at the top level; secret renamed inconsistently; secret intended to be supplied externally but not marked `external: true`.","solutions":["Declare the secret in the top-level `secrets:` block (from file, environment, or external).","For secrets already in Swarm, use `external: true` with the real name.","Correct the service's secret name to match an existing declaration."],"exampleFix":"// before\nservices:\n  app:\n    image: myapp\n    secrets: [db-password]\n// after\nservices:\n  app:\n    image: myapp\n    secrets: [db-password]\nsecrets:\n  db-password:\n    external: true","handlingStrategy":"validation","validationCode":"func validateSecretsDeclared(cfg *composetypes.Config) error {\n    for _, svc := range cfg.Services {\n        for _, s := range svc.Secrets {\n            if _, ok := cfg.Secrets[s.Source]; !ok {\n                return fmt.Errorf(\"undefined secret %q\", s.Source)\n            }\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair a service's `secrets:` entry with a top-level `secrets:` declaration.","Mark Swarm-managed secrets external: true.","Automate a config-lint step in CI."],"tags":["compose","convert","secrets","swarm","undefined"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}