docker/cli · error

no files specified

Error message

no files specified

What it means

Returned by loader.Load when configDetails.ConfigFiles is empty. Load requires at least one config file to merge and interpolate; with zero files there is nothing to parse. This is an explicit guard before the load loop begins processing.

Solutions

  1. Ensure at least one types.ConfigFile (or the default docker-compose.yaml) is appended to configDetails.ConfigFiles before calling Load.
  2. If reading from stdin, add a ConfigFile with Filename set to '-' and Content set to the stdin bytes.
  3. Default to the conventional filename ('compose.yaml') when no explicit files are provided.

Example fix

// before
details := types.ConfigDetails{ConfigFiles: []types.ConfigFile{}}
cfg, err := loader.Load(details)
// after
details := types.ConfigDetails{
  ConfigFiles: []types.ConfigFile{{Filename: "compose.yaml", Content: data}},
}
cfg, err := loader.Load(details)
Defensive patterns

Strategy: validation

Validate before calling

if len(details.ConfigFiles) == 0 {
    details.ConfigFiles = append(details.ConfigFiles, types.ConfigFile{
        Filename: "compose.yaml",
        Content:  defaultBytes,
    })
}
cfg, err := loader.Load(details)

Prevention

When it happens

Trigger: Constructing a types.ConfigDetails and calling Load without appending any entry to ConfigFiles. A CLI path that resolves --file flags but passes an empty slice because all flags were filtered out or the file did not exist and was silently skipped.

Common situations: A wrapper script building ConfigDetails programmatically forgets to populate ConfigFiles. A -f/--filename argument was consumed but the resolved path list came back empty due to a glob that matched nothing.

Related errors


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

Appendix: source

Thrown at cli/compose/loader/loader.go:81

	var cfg any
	if err := yaml.Unmarshal(source, &cfg); err != nil {
		return nil, err
	}
	_, ok := cfg.(map[string]any)
	if !ok {
		return nil, errors.New("top-level object must be a mapping")
	}
	converted, err := convertToStringKeysRecursive(cfg, "")
	if err != nil {
		return nil, err
	}
	return converted.(map[string]any), nil
}

// Load reads a ConfigDetails and returns a fully loaded configuration
func Load(configDetails types.ConfigDetails, opt ...func(*Options)) (*types.Config, error) {
	if len(configDetails.ConfigFiles) < 1 {
		return nil, errors.New("no files specified")
	}

	options := &Options{
		Interpolate: &interp.Options{
			Substitute:      template.Substitute,
			LookupValue:     configDetails.LookupEnv,
			TypeCastMapping: interpolateTypeCastMapping,
		},
	}

	for _, op := range opt {
		op(options)
	}

	configs := []*types.Config{}
	var err error

	for _, file := range configDetails.ConfigFiles {

View on GitHub (pinned to 4f84911bfe)