{"record":{"id":"3fd9ed422ed9eda8","repo":"docker/cli","slug":"no-files-specified","errorCode":null,"errorMessage":"no files specified","messagePattern":"no files specified","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/compose/loader/loader.go","lineNumber":81,"sourceCode":"\tvar cfg any\n\tif err := yaml.Unmarshal(source, &cfg); err != nil {\n\t\treturn nil, err\n\t}\n\t_, ok := cfg.(map[string]any)\n\tif !ok {\n\t\treturn nil, errors.New(\"top-level object must be a mapping\")\n\t}\n\tconverted, err := convertToStringKeysRecursive(cfg, \"\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn converted.(map[string]any), nil\n}\n\n// Load reads a ConfigDetails and returns a fully loaded configuration\nfunc Load(configDetails types.ConfigDetails, opt ...func(*Options)) (*types.Config, error) {\n\tif len(configDetails.ConfigFiles) < 1 {\n\t\treturn nil, errors.New(\"no files specified\")\n\t}\n\n\toptions := &Options{\n\t\tInterpolate: &interp.Options{\n\t\t\tSubstitute:      template.Substitute,\n\t\t\tLookupValue:     configDetails.LookupEnv,\n\t\t\tTypeCastMapping: interpolateTypeCastMapping,\n\t\t},\n\t}\n\n\tfor _, op := range opt {\n\t\top(options)\n\t}\n\n\tconfigs := []*types.Config{}\n\tvar err error\n\n\tfor _, file := range configDetails.ConfigFiles {","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cli/compose/loader/loader.go#L63-L99","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure at least one types.ConfigFile (or the default docker-compose.yaml) is appended to configDetails.ConfigFiles before calling Load.","If reading from stdin, add a ConfigFile with Filename set to '-' and Content set to the stdin bytes.","Default to the conventional filename ('compose.yaml') when no explicit files are provided."],"exampleFix":"// before\ndetails := types.ConfigDetails{ConfigFiles: []types.ConfigFile{}}\ncfg, err := loader.Load(details)\n// after\ndetails := types.ConfigDetails{\n  ConfigFiles: []types.ConfigFile{{Filename: \"compose.yaml\", Content: data}},\n}\ncfg, err := loader.Load(details)","handlingStrategy":"validation","validationCode":"if len(details.ConfigFiles) == 0 {\n    details.ConfigFiles = append(details.ConfigFiles, types.ConfigFile{\n        Filename: \"compose.yaml\",\n        Content:  defaultBytes,\n    })\n}\ncfg, err := loader.Load(details)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always default to a conventional filename when no -f is given.","Assert len(ConfigFiles) > 0 in a helper that wraps Load.","Unit-test the wrapper with an empty ConfigFiles to confirm it provides a default."],"tags":["compose","loader","validation","api-usage"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}