docker/cli · error
undefined config
Error message
undefined config %q
What it means
Returned by the config lookup closure inside convertServiceConfigObjs when a config referenced by a service is absent from the top-level configSpecs map (service.go:300-303). Compose configs (Swarm configs) must be declared before use.
Solutions
- Add the config under the top-level `configs:` key (file-backed or external).
- If it already exists in Swarm, declare it `external: true` with its real name.
- Fix the service's config name to match an existing declaration.
Example fix
// before
services:
web:
image: nginx
configs:
- site.conf
// after
services:
web:
image: nginx
configs:
- site.conf
configs:
site.conf:
file: ./site.conf Defensive patterns
Strategy: validation
Validate before calling
func validateConfigsDeclared(cfg *composetypes.Config) error {
for _, svc := range cfg.Services {
for _, c := range svc.Configs {
if _, ok := cfg.Configs[c.Source]; !ok {
return fmt.Errorf("undefined config %q", c.Source)
}
}
}
return nil
} Prevention
- Pair every service `configs:` entry with a top-level `configs:` declaration.
- Use external: true for configs already in Swarm.
- Lint compose files in CI before deploy.
When it happens
Trigger: A service's `configs:` list references a config not declared in the top-level `configs:` block; the lookup at service.go:301 returns false.
Common situations: Config mounted into a service but never declared; renamed a config in only one location; intended to use an external Swarm config but forgot `external: true`.
Related errors
- undefined network
- undefined secret
- invalid credential spec: spec specifies config
- service
- invalid restart policy: unknown policy
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/f3ff3445433d0837.
Report an issue: GitHub.
Appendix: source
Thrown at cli/compose/convert/service.go:302
// and a set of compose Config specs, and creates the swarm ConfigReferences
// required by the service. Unlike convertServiceSecrets, this takes the whole
// ServiceConfig, because some Configs may be needed as a result of other
// fields (like CredentialSpecs).
//
// TODO: fix configs API so that ConfigsAPIClient is not required here
func convertServiceConfigObjs(
ctx context.Context,
apiClient client.ConfigAPIClient,
namespace Namespace,
service composetypes.ServiceConfig,
configSpecs map[string]composetypes.ConfigObjConfig,
) ([]*swarm.ConfigReference, error) {
refs := []*swarm.ConfigReference{}
lookup := func(key string) (composetypes.FileObjectConfig, error) {
configSpec, exists := configSpecs[key]
if !exists {
return composetypes.FileObjectConfig{}, fmt.Errorf("undefined config %q", key)
}
return composetypes.FileObjectConfig(configSpec), nil
}
for _, config := range service.Configs {
obj, err := convertFileObject(namespace, composetypes.FileReferenceConfig(config), lookup)
if err != nil {
return nil, err
}
file := swarm.ConfigReferenceFileTarget(obj.File)
refs = append(refs, &swarm.ConfigReference{
File: &file,
ConfigName: obj.Name,
})
}
// finally, after converting all file objects, create any
// Runtime-type configs that are needed. these are configs that are notView on GitHub (pinned to 4f84911bfe)