{"record":{"id":"6b3414b9abfd9ca4","repo":"grafana/k6","slug":"could-not-open-s-w","errorCode":null,"errorMessage":"could not open '%s': %w","messagePattern":"could not open '(.+?)': %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cmd/run.go","lineNumber":594,"sourceCode":"}\n\nfunc handleSummaryResult(fs fsext.Fs, stdOut, stdErr io.Writer, result map[string]io.Reader) error {\n\tvar errs []error\n\n\tgetWriter := func(path string) (io.Writer, error) {\n\t\tswitch path {\n\t\tcase \"stdout\":\n\t\t\treturn stdOut, nil\n\t\tcase \"stderr\":\n\t\t\treturn stdErr, nil\n\t\tdefault:\n\t\t\treturn fs.OpenFile(path, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_TRUNC, 0o666)\n\t\t}\n\t}\n\n\tfor path, value := range result {\n\t\tif writer, err := getWriter(path); err != nil {\n\t\t\terrs = append(errs, fmt.Errorf(\"could not open '%s': %w\", path, err))\n\t\t} else if n, err := io.Copy(writer, value); err != nil {\n\t\t\terrs = append(errs, fmt.Errorf(\"error saving summary to '%s' after %d bytes: %w\", path, n, err))\n\t\t}\n\t}\n\n\treturn consolidateErrorMessage(errs, \"Could not save some summary information:\")\n}\n","sourceCodeStart":576,"sourceCodeEnd":602,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/cmd/run.go#L576-L602","documentation":"When the end-of-test summary is exported to files (handleSummary returning a map of paths to data, or --summary-export), k6 opens each path with O_WRONLY|O_CREAT|O_TRUNC via getWriter (only 'stdout' and 'stderr' are special-cased). If the file cannot be created or opened, the error is wrapped as \"could not open '<path>'\" and consolidated with other summary failures under 'Could not save some summary information:'.","triggerScenarios":"handleSummary returns { 'out/reports/summary.json': JSON.stringify(data) } where out/reports/ does not exist; --summary-export points into a directory the k6 process cannot write; a directory component of the path is actually a regular file.","commonSituations":"CI containers writing summaries into directories never created in the image; paths on read-only mounts; typos in summary paths; switching summary output from stdout to a file without creating the folder.","solutions":["Create the parent directory before the run: mkdir -p out/reports","Use the special keys 'stdout' or 'stderr' in handleSummary when no file output is needed","Verify the target directory exists and is writable by the k6 process user","Treat every non-stdout/stderr key of handleSummary's return map as a file path that must be creatable, and validate them all"],"exampleFix":"// before\nexport function handleSummary(data) {\n  return { 'reports/summary.json': JSON.stringify(data) };\n}\n// after\nexport function handleSummary(data) {\n  return { stdout: textSummary(data), 'reports/summary.json': JSON.stringify(data) };\n}\n// plus in the shell: mkdir -p reports before k6 run","handlingStrategy":"validation","validationCode":"# Pre-create and verify every summary target directory\nmkdir -p reports out\n[ -w reports ] || { echo 'reports/ is not writable' >&2; exit 2; }\nk6 run --summary-export=reports/summary.json script.js","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use only 'stdout'/'stderr' or pre-created directories in handleSummary return maps","Create summary directories in the CI job setup step","Avoid absolute paths owned by other users (/var, /run)","Validate all file paths once in a shared config before the run"],"tags":["summary","filesystem","io","handle-summary"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}