{"record":{"id":"becdedfaf2e3bfb2","repo":"grafana/k6","slug":"removing-downloads-path-w","errorCode":null,"errorMessage":"removing downloads path: %w","messagePattern":"removing downloads path: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/js/modules/k6/browser/common/browser_context.go","lineNumber":112,"sourceCode":"func (b *BrowserContext) setDownloadsPath(path string) error {\n\tpath = strings.TrimSpace(path)\n\tif path != \"\" {\n\t\tb.DownloadsPath = path\n\t\treturn nil\n\t}\n\tdir, err := os.MkdirTemp(os.TempDir(), artifactsDirectory+\"*\") //nolint:forbidigo\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating temporary directory for downloads: %w\", err)\n\t}\n\tb.DownloadsPath = dir\n\n\treturn nil\n}\n\n// cleanup cleans up the resources associated with the browser context.\nfunc (b *BrowserContext) cleanup() error {\n\tif err := os.RemoveAll(b.DownloadsPath); err != nil { //nolint:forbidigo\n\t\treturn fmt.Errorf(\"removing downloads path: %w\", err)\n\t}\n\tb.DownloadsPath = \"\"\n\n\treturn nil\n}\n\n// NewBrowserContext creates a new browser context.\nfunc NewBrowserContext(\n\tctx context.Context, browser *Browser, id cdp.BrowserContextID, opts *BrowserContextOptions, logger *log.Logger,\n) (*BrowserContext, error) {\n\t// set the default options if none provided.\n\tif opts == nil {\n\t\topts = DefaultBrowserContextOptions()\n\t}\n\t// Always use the [Browser]'s user agent if it's not set by the user.\n\t// Setting this forces [FrameSession] to set Chromium's user agent.\n\tif strings.TrimSpace(opts.UserAgent) == \"\" {\n\t\topts.UserAgent = browser.UserAgent()","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/browser_context.go#L94-L130","documentation":"During BrowserContext.cleanup (browser_context.go:112), k6 runs os.RemoveAll on the downloads directory it created for the context. If the removal fails — permission loss, files held open, failing mount — the error is wrapped as 'removing downloads path: %w'. The context itself is still considered closed; the practical impact is a leaked temp directory.","triggerScenarios":"Files in the download directory still held/locked by another process; directory on NFS/FUSE returning errors; the k6 process losing permission (uid change, SELinux); path already altered by concurrent cleanup.","commonSituations":"Downloaded files still open when the context closes; exotic mounts in CI; leftover /tmp/artifacts-* dirs accumulating after repeated failures.","solutions":["Check the wrapped syscall error (EACCES/EBUSY) and fix permissions or close file handles before context close","Clean leftover artifacts-* dirs under /tmp between runs","Use an explicit downloadsPath on a volume you manage so cleanup is deterministic"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// close file handles and stop writers before ending the context\n// use an explicit downloadsPath you control to make cleanup predictable","typeGuard":null,"tryCatchPattern":"try {\n  await ctx.close()\n} catch (e) {\n  if (/removing downloads path/.test(String(e))) {\n    // context is closed; schedule manual cleanup of the leaked artifacts-* dir\n  } else throw e\n}","preventionTips":["Close downloaded files before closing the context","Use an explicit downloadsPath so cleanup does not depend on /tmp","Sweep leftover artifacts-* dirs between CI runs"],"tags":["filesystem","cleanup","downloads","leak"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}