{"record":{"id":"d824a578ee54886e","repo":"docker/compose","slug":"cannot-create-output-folder-w","errorCode":null,"errorMessage":"cannot create output folder: %w","messagePattern":"cannot create output folder: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/bridge/convert.go","lineNumber":76,"sourceCode":"\t\treturn err\n\t}\n\t// for user to rely on compose.yaml attribute names, not go struct ones, we marshall back into YAML\n\traw, err := project.MarshalYAML(types.WithSecretContent)\n\t// Marshall to YAML\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot render project into yaml: %w\", err)\n\t}\n\tvar model map[string]any\n\terr = yaml.Unmarshal(raw, &model)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot render project into yaml: %w\", err)\n\t}\n\n\tif opts.Output != \"\" {\n\t\t_ = os.RemoveAll(opts.Output)\n\t\terr := os.MkdirAll(opts.Output, 0o744)\n\t\tif err != nil && !os.IsExist(err) {\n\t\t\treturn fmt.Errorf(\"cannot create output folder: %w\", err)\n\t\t}\n\t}\n\t// Run Transformers images\n\treturn convert(ctx, dockerCli, model, opts)\n}\n\nfunc convert(ctx context.Context, dockerCli command.Cli, model map[string]any, opts ConvertOptions) error {\n\traw, err := yaml.Marshal(model)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdir, err := os.MkdirTemp(\"\", \"compose-convert-*\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer func() {\n\t\terr := os.RemoveAll(dir)","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/docker/compose/blob/ddc4b044b62e9f715212ea4143fa830fac76382f/pkg/bridge/convert.go#L58-L94","documentation":"When bridge.Convert is called with opts.Output set, it first removes any existing directory at that path (os.RemoveAll) and then recreates it with os.MkdirAll(out, 0o744). This error means the recreation failed for a reason other than the directory already existing — the %w wraps the mkdir error. Typical causes are a parent that is not writable, a path component that is a file, or read-only filesystems.","triggerScenarios":"Calling bridge.Convert with Output pointing under a directory without write permission; Output whose parent path contains a regular file; Output on a read-only mount; a race where another process recreates the path as a file between RemoveAll and MkdirAll.","commonSituations":"CI containers running as a non-root user writing to /output or another root-owned path; converting to a path inside a read-only bind mount; a leftover file (not directory) at the Output path.","solutions":["Check permissions on the parent directory and grant write access (chmod/chown) or choose a writable Output path","Verify no regular file occupies the Output path or any parent component (ls -l on each segment)","If Output is a bind mount, ensure it is mounted read-write","Run the command with a fresh Output under a temp dir to confirm the rest of the conversion works"],"exampleFix":"# before\n$ docker compose ... --output /opt/results\nmkdir: permission denied\n# after\n$ sudo chown -R $(id -u) /opt/results  # or\n$ docker compose ... --output ./results\n","handlingStrategy":"validation","validationCode":"// Before Convert with Output set:\nif opts.Output != \"\" {\n\tif err := os.MkdirAll(opts.Output, 0o744); err != nil {\n\t\treturn fmt.Errorf(\"output path not writable: %w\", err)\n\t}\n\tif info, err := os.Stat(opts.Output); err != nil || !info.IsDir() {\n\t\treturn fmt.Errorf(\"output path %s is not a writable directory\", opts.Output)\n\t}\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pre-create the output directory in CI setup and assert writability with a touch-file","Avoid paths on read-only mounts or under root-owned dirs when running as non-root","Clean stale outputs before conversion in scripts"],"tags":["filesystem","permissions","bridge","convert"],"backgroundTag":null,"analyzedSha":"ddc4b044b62e9f715212ea4143fa830fac76382f","analyzedAt":"2026-08-15T13:31:42.319Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}