{"record":{"id":"0eafc413f9abd9db","repo":"grafana/k6","slug":"w","errorCode":null,"errorMessage":"%w","messagePattern":"%w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/browser_process.go","lineNumber":166,"sourceCode":"\treturn p.meta.Cleanup() //nolint:wrapcheck\n}\n\ntype command struct {\n\t*exec.Cmd\n\tdone           chan struct{}\n\tstdout, stderr io.Reader\n}\n\nfunc execute(\n\tctx context.Context, path string, args []string,\n\tdataDir *storage.Dir, logger *log.Logger,\n) (command, error) {\n\tcmd := exec.CommandContext(ctx, path, args...) //nolint:gosec\n\tkillAfterParent(cmd)\n\n\tstdout, err := cmd.StdoutPipe()\n\tif err != nil {\n\t\treturn command{}, fmt.Errorf(\"%w\", err)\n\t}\n\tstderr, err := cmd.StderrPipe()\n\tif err != nil {\n\t\treturn command{}, fmt.Errorf(\"%w\", err)\n\t}\n\n\t// We must start the cmd before calling cmd.Wait, as otherwise the two\n\t// can run into a data race.\n\terr = cmd.Start()\n\tif os.IsNotExist(err) { //nolint:forbidigo\n\t\treturn command{}, fmt.Errorf(\"file does not exist: %s\", path)\n\t}\n\tif err != nil {\n\t\treturn command{}, fmt.Errorf(\"%w\", err)\n\t}\n\tif ctx.Err() != nil {\n\t\treturn command{}, ContextErr(ctx)\n\t}","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/browser_process.go#L148-L184","documentation":"While spawning the browser process, k6 calls cmd.StdoutPipe(); if the OS refuses to create the pipe, the raw error is wrapped and returned. This is an environment-level failure before the browser even starts, almost always file-descriptor exhaustion (EMFILE) or a fork/resource limit.","triggerScenarios":"Launching a browser when the k6 process has hit its open-file limit (ulimit -n) — typically with many concurrent VUs each spawning a browser and websocket connections.","commonSituations":"High concurrency browser scenarios on CI runners with low default ulimits; leaking chrome processes from previous crashed runs; long soak tests accumulating descriptors.","solutions":["Check the limit with ulimit -n and raise it (e.g. ulimit -n 4096 or the systemd/containers equivalent).","Kill orphaned chrome/chromium processes from earlier failed runs before starting the test.","Reduce the number of parallel browser VUs (scenario vus/maxVUs) to lower simultaneous process spawns."],"exampleFix":"# before\nulimit -n 1024\nk6 run browser-test.js  # fails with wrapped pipe error\n\n# after\nulimit -n 8192\nk6 run browser-test.js","handlingStrategy":"validation","validationCode":"# fail fast if the fd limit is too low for parallel browser VUs\nOPEN=$(ulimit -n)\nif [ \"$OPEN\" -lt 2048 ]; then\n  echo \"open-file limit $OPEN is too low for browser scenarios\" >&2; exit 1\nfi","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set ulimit -n (or container --ulimit nofile) explicitly in run environments.","Clean up orphaned chromium processes between runs (pkill -f 'chrome.*user-data-dir' or dedicated user-data dirs).","Cap concurrent browser VUs to keep descriptor usage bounded."],"tags":["process","os","file-descriptors","concurrency"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}