{"record":{"id":"c7aaa8df15a31016","repo":"GopeedLab/gopeed","slug":"invalid-waituntil-s","errorCode":null,"errorMessage":"invalid waitUntil: %s","messagePattern":"invalid waitUntil: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/download/engine/webview/runtime.go","lineNumber":504,"sourceCode":"\t\treturn GotoOptions{}, err\n\t}\n\treturn GotoOptions{\n\t\tTimeoutMS: parseInt64(raw[\"timeoutMs\"]),\n\t\tWaitUntil: waitUntil,\n\t}, nil\n}\n\nfunc normalizeWaitUntil(raw string) (string, error) {\n\tif raw == \"\" {\n\t\treturn \"load\", nil\n\t}\n\tswitch strings.ToLower(strings.TrimSpace(raw)) {\n\tcase \"load\":\n\t\treturn \"load\", nil\n\tcase \"domcontentloaded\":\n\t\treturn \"domcontentloaded\", nil\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"invalid waitUntil: %s\", raw)\n\t}\n}\n\nfunc parseClickOptions(raw map[string]any) ClickOptions {\n\treturn ClickOptions{DelayMS: parseInt64(raw[\"delay\"])}\n}\n\nfunc parseTypeOptions(raw map[string]any) TypeOptions {\n\treturn TypeOptions{DelayMS: parseInt64(raw[\"delay\"])}\n}\n\nfunc parseWaitOptions(raw map[string]any) WaitOptions {\n\treturn WaitOptions{\n\t\tTimeoutMS:      parseInt64(raw[\"timeoutMs\"]),\n\t\tPollIntervalMS: parseInt64(raw[\"pollIntervalMs\"]),\n\t}\n}\n","sourceCodeStart":486,"sourceCodeEnd":522,"githubUrl":"https://github.com/GopeedLab/gopeed/blob/7b7327ffb30816273a74b142cccc0bc10c5a4c67/pkg/download/engine/webview/runtime.go#L486-L522","documentation":"normalizeWaitUntil validates the waitUntil option of page.goto. Unlike Playwright/Puppeteer, this webview layer supports only 'load' (the default when empty) and 'domcontentloaded', compared case-insensitively after trimming. Any other string — notably 'networkidle', 'networkidle0', 'networkidle2', 'commit' — is rejected.","triggerScenarios":"page.goto(url, {waitUntil: 'networkidle'}) copied from a Playwright script; passing 'networkidle0' from Puppeteer habits; a typo like 'load ' (handled) vs 'loaded' (rejected).","commonSituations":"Porting browser-automation code from Puppeteer/Playwright to a gopeed extension; waiting for XHR-driven SPAs where authors reach for networkidle by reflex.","solutions":["Use 'domcontentloaded' plus waitForSelector/waitForFunction for data-driven pages instead of networkidle","Omit waitUntil entirely when 'load' semantics are fine","Lower-case and trim the value if it comes from user config"],"exampleFix":"// before\nawait page.goto(url, { waitUntil: 'networkidle' }); // -> invalid waitUntil: networkidle\n// after\nawait page.goto(url, { waitUntil: 'domcontentloaded' });\nawait page.waitForSelector('.result-item');","handlingStrategy":"validation","validationCode":"// JS: whitelist before goto\nconst WAIT_UNTIL = new Set(['load', 'domcontentloaded']);\nfunction normWaitUntil(v) {\n  const s = String(v || '').trim().toLowerCase();\n  return WAIT_UNTIL.has(s) ? s : 'load';\n}\nawait page.goto(url, { waitUntil: normWaitUntil(cfg.waitUntil) });","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Remember only load and domcontentloaded exist — no networkidle","Replace networkidle waits with waitForSelector on the data marker","Normalize config-supplied values through a whitelist helper"],"tags":["webview","goto","options","browser-automation","playwright-compat"],"backgroundTag":null,"analyzedSha":"7b7327ffb30816273a74b142cccc0bc10c5a4c67","analyzedAt":"2026-08-16T02:51:03.250Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}