{"record":{"id":"336c7fb92651db4f","repo":"grafana/k6","slug":"persisting-screenshot-w","errorCode":null,"errorMessage":"persisting screenshot: %w","messagePattern":"persisting screenshot: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/screenshotter.go","lineNumber":234,"sourceCode":"\t}\n\n\t// Capture screenshot\n\tbuf, err = capture.Do(cdp.WithExecutor(s.ctx, sess))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"capturing screenshot: %w\", err)\n\t}\n\n\tif shouldSetDefaultBackground {\n\t\taction := emulation.SetDefaultBackgroundColorOverride()\n\t\tif err := action.Do(cdp.WithExecutor(s.ctx, sess)); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"resetting screenshot background color: %w\", err)\n\t\t}\n\t}\n\n\t// Save screenshot capture to file\n\tif path != \"\" {\n\t\tif err := s.persister.Persist(s.ctx, path, bytes.NewBuffer(buf)); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"persisting screenshot: %w\", err)\n\t\t}\n\t}\n\n\treturn buf, nil\n}\n\nfunc getViewPortDimensions(ctx context.Context, sess session, logger *log.Logger) (float64, float64, float64, error) {\n\tvisualViewportScale := 1.0\n\tvisualViewportPageX, visualViewportPageY := 0.0, 0.0\n\n\t// Add clip region\n\t//nolint:dogsled\n\t_, _, _, _, cssVisualViewport, _, err := cdppage.GetLayoutMetrics().Do(cdp.WithExecutor(ctx, sess))\n\tif err != nil {\n\t\treturn 0, 0, 0, fmt.Errorf(\"getting layout metrics for screenshot: %w\", err)\n\t}\n\n\t// we had a null pointer panic cases, when visualViewport is nil","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/screenshotter.go#L216-L252","documentation":"The screenshot was captured successfully, but writing it to disk through the ScreenshotPersister failed. This is a filesystem/IO error on the k6 host side — the bytes in memory are fine, only persistence failed.","triggerScenarios":"page.screenshot({path: '...'}) where the path is unwritable: directory does not exist, permission denied, read-only filesystem, path too long, or disk full. Also container setups where the working dir is not writable.","commonSituations":"Using an absolute path like /home/... or /root/... that the k6 process cannot write; assuming mkdir happens automatically; running k6 in Docker with no mounted writable volume; CI sandboxes with read-only workspaces; Windows path separators in scripts written on Linux.","solutions":["Write to an existing, writable directory — use a relative path like 'screenshots/shot.png' after creating the folder, or '.'.","Check permissions of the target directory for the user running k6 (and mount a writable volume in Docker).","If you only need the bytes, drop the path option and handle the returned Buffer yourself.","Verify disk space on the target filesystem."],"exampleFix":"// before\nawait page.screenshot({ path: '/var/data/shots/home.png' }); // dir may not exist / no perms\n\n// after (shell): mkdir -p screenshots\nawait page.screenshot({ path: 'screenshots/home.png' });","handlingStrategy":"validation","validationCode":"import { execSync } from 'k6/x/...' // not available; instead verify writability in the shell before the run:\n// mkdir -p screenshots && touch screenshots/.probe && rm screenshots/.probe","typeGuard":null,"tryCatchPattern":"try { await page.screenshot({ path: 'screenshots/s.png' }); }\ncatch (e) { if (String(e).includes('persisting screenshot')) { const buf = await page.screenshot(); /* use buf */ } else throw e; }","preventionTips":["Pre-create the screenshots directory in CI before running k6.","Use relative paths under the (writable) working directory.","Mount a writable volume when running k6 in Docker.","Skip the path option if you only need the bytes."],"tags":["k6","browser","screenshot","filesystem","permissions","io"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}