{"record":{"id":"0c7a6792308cb8dd","repo":"projectdiscovery/katana","slug":"could-not-enable-fetch-domain","errorCode":null,"errorMessage":"could not enable fetch domain","messagePattern":"could not enable fetch domain","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/engine/headless/browser/browser.go","lineNumber":505,"sourceCode":"// It combines the functionality of BackoffSleeper and CountSleeper.\nfunc backoffCountSleeper(initInterval, maxInterval time.Duration, maxAttempts int, algorithm func(time.Duration) time.Duration) rodutils.Sleeper {\n\tbackoff := rodutils.BackoffSleeper(initInterval, maxInterval, algorithm)\n\tcount := rodutils.CountSleeper(maxAttempts)\n\n\treturn rodutils.EachSleepers(backoff, count)\n}\n\nfunc (b *BrowserPage) handlePageDialogBoxes() error {\n\terr := proto.FetchEnable{\n\t\tPatterns: []*proto.FetchRequestPattern{\n\t\t\t{\n\t\t\t\tURLPattern:   \"*\",\n\t\t\t\tRequestStage: proto.FetchRequestStageResponse,\n\t\t\t},\n\t\t},\n\t}.Call(b.Page)\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"could not enable fetch domain\")\n\t}\n\n\tgo b.EachEvent(\n\t\tfunc(e *proto.PageJavascriptDialogOpening) {\n\t\t\t_ = proto.PageHandleJavaScriptDialog{\n\t\t\t\tAccept:     true,\n\t\t\t\tPromptText: xid.New().String(),\n\t\t\t}.Call(b.Page)\n\t\t},\n\n\t\tfunc(e *proto.FetchRequestPaused) {\n\t\t\tif b.launcher.opts.CookieConsentBypass {\n\t\t\t\t// Check if request should be blocked by cookie consent rules\n\t\t\t\tvar originStr string\n\t\t\t\tif origin, ok := e.Request.Headers[\"Origin\"]; ok {\n\t\t\t\t\toriginStr = origin.Str()\n\t\t\t\t}\n\t\t\t\tif cookie.ShouldBlockRequest(e.Request.URL, e.ResourceType, originStr) {","sourceCodeStart":487,"sourceCodeEnd":523,"githubUrl":"https://github.com/projectdiscovery/katana/blob/e3e742739c3746f085943ce918fb4e2b8daf6fe6/pkg/engine/headless/browser/browser.go#L487-L523","documentation":"handlePageDialogBoxes (called during page creation) enables the Chrome DevTools Fetch domain via proto.FetchEnable{...}.Call(b.Page) so katana can intercept responses and auto-dismiss JS dialogs; failure is wrapped as 'could not enable fetch domain'. This means the CDP Fetch.enable command was rejected — usually because the page/browser session is dead or the domain is already in an inconsistent state.","triggerScenarios":"Calling FetchEnable on a page whose CDP connection is closed or whose target crashed, on an already-disconnected remote browser, or when the underlying session returns 'session not found' / 'target closed' during browser page setup.","commonSituations":"Chrome dying between page creation and dialog-handler setup in fast-crawl/high-concurrency runs; using a stale remote debugging endpoint (ChromeWSUrl) that has dropped; older Chrome builds with Fetch domain quirks; page pool reuse after the browser was closed.","solutions":["Check the wrapped error for 'target closed'/'session not found' and recreate the browser page (the whole createBrowserPageFunc path) instead of retrying FetchEnable.","Verify the Chrome instance is alive and the remote debugging WebSocket URL is valid and reachable.","Lower crawl concurrency so Chrome is not killed by resource exhaustion mid-setup.","Update Chrome/katana to matching versions so the Fetch domain behaves as expected."],"exampleFix":"// before: ignoring why fetch enable failed\nif err := browserPage.handlePageDialogBoxes(); err != nil { return err }\n\n// after: recreate the page when the session is dead\nif err := browserPage.handlePageDialogBoxes(); err != nil {\n    if strings.Contains(err.Error(), \"target closed\") || strings.Contains(err.Error(), \"session\") {\n        return l.createBrowserPageFunc() // fresh browser/page\n    }\n    return err\n}","handlingStrategy":"try-catch","validationCode":"// confirm CDP session is usable before enabling Fetch\nif page.GetContext().Err() != nil {\n    return fmt.Errorf(\"cannot enable fetch domain: page session dead\")\n}","typeGuard":null,"tryCatchPattern":"if err := proto.FetchEnable{Patterns: ...}.Call(page); err != nil {\n    if strings.Contains(err.Error(), \"already enabled\") {\n        return nil // idempotent: treat as success\n    }\n    return errors.Wrap(err, \"could not enable fetch domain\") // dead session: recreate page\n}","preventionTips":["Validate remote debugging WS URLs before long-running jobs.","Recycle pages instead of reusing them after errors (poisoned sessions).","Cap concurrency to avoid Chrome crashes during setup.","Log the wrapped cause to distinguish dead sessions from protocol errors."],"tags":["headless-browser","cdp","fetch-domain","rod"],"backgroundTag":"cdp-session-not-found","analyzedSha":"e3e742739c3746f085943ce918fb4e2b8daf6fe6","analyzedAt":"2026-09-03T14:55:13.248Z","contentChangedAt":"2026-09-03T14:55:13.248Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}