{"record":{"id":"f27b112100675915","repo":"jackwener/OpenCLI","slug":"linux-do-returned-an-empty-browser-response","errorCode":null,"errorMessage":"linux.do returned an empty browser response","messagePattern":"linux\\.do returned an empty browser response","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/linux-do/feed.js","lineNumber":100,"sourceCode":"    try {\n      const res = await fetch(${escapedPath}, { credentials: 'include' });\n      let data = null;\n      try { data = await res.json(); } catch {}\n      return {\n        ok: res.ok,\n        status: res.status,\n        data,\n        error: data === null ? 'Response is not valid JSON' : '',\n      };\n    } catch (error) {\n      return {\n        ok: false,\n        error: error instanceof Error ? error.message : String(error),\n      };\n    }\n  })()`);\n    if (!result) {\n        throw new CommandExecutionError('linux.do returned an empty browser response');\n    }\n    if (result.status === 401 || result.status === 403) {\n        throw new AuthRequiredError('linux.do', 'linux.do requires an active signed-in browser session');\n    }\n    if (!result.ok) {\n        throw new CommandExecutionError(result.error || `linux.do request failed: HTTP ${result.status ?? 'unknown'}`);\n    }\n    if (result.error) {\n        throw new CommandExecutionError(result.error, 'Please verify your linux.do session is still valid');\n    }\n    return result.data;\n}\nfunction findMatchingTag(records, value) {\n    const raw = value.trim();\n    const normalized = normalizeLookupValue(value);\n    return /^\\d+$/.test(raw)\n        ? records.find((item) => item.id === Number(raw)) ?? null\n        : records.find((item) => normalizeLookupValue(item.name) === normalized)","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linux-do/feed.js#L82-L118","documentation":"fetchLinuxDoJson runs its HTTP request inside the browser page via page.evaluate and expects the async IIFE to resolve to a result object ({ok, status, data, error} or {ok:false, error}). This CommandExecutionError is thrown when evaluate resolves to null/undefined — the page returned nothing to inspect. The library treats an empty response as a command-execution failure because it cannot distinguish success from any error class (auth, HTTP, JSON) without the result envelope.","triggerScenarios":"The page context was destroyed mid-evaluate (tab closed, navigation, browser crash) so evaluate resolves null/undefined; the automation driver's evaluate fails to serialize the return value; calling with a page from a different origin/frame where the IIFE is blocked; intermittent driver bug where the evaluated promise is cancelled.","commonSituations":"linux.do redirects or the user closes the automation window while feed data is loading; browser crashes under memory pressure during large metadata fan-out (categories.json subcategory loop); stale page object reused after browser restart; driver/CDP version incompatibilities swallowing the evaluate result.","solutions":["Retry the command — this is often transient (a navigation or hiccup during evaluate). The CLI metadata cache may serve stale-but-valid tags/categories on retry.","Ensure nothing navigates or closes the page during the evaluate; call fetchLinuxDoJson with skipNavigate: true after navigation has settled (networkidle).","Reopen a fresh page to https://linux.do and rerun if the page context may have been destroyed.","If it reproduces every time, check browser/driver versions for evaluate serialization bugs and update the automation runtime."],"exampleFix":"// before\nawait page.goto('https://linux.do');\nconst data = await fetchLinuxDoJson(page, '/latest.json'); // page navigated concurrently -> null result\n// after\nawait page.goto('https://linux.do');\nawait page.waitForLoadState('networkidle');\nconst data = await fetchLinuxDoJson(page, '/latest.json', { skipNavigate: true });","handlingStrategy":"retry","validationCode":"if (!page || (typeof page.isClosed === 'function' && page.isClosed())) {\n  throw new Error('Page is gone — reopen it before fetching linux.do JSON');\n}","typeGuard":"function hasResultEnvelope(r) {\n  return !!r && typeof r === 'object' && typeof r.ok === 'boolean' &&\n    ('status' in r || 'error' in r);\n}","tryCatchPattern":"try {\n  const data = await fetchLinuxDoJson(page, path, { skipNavigate: true });\n} catch (err) {\n  if (/empty browser response/.test(err.message)) {\n    // transient context loss — reopen page, settle navigation, retry once\n    page = await browser.newPage();\n    await page.goto('https://linux.do');\n    await page.waitForLoadState('networkidle');\n    return fetchLinuxDoJson(page, path, { skipNavigate: true });\n  }\n  if (err instanceof AuthRequiredError) return promptLogin();\n  throw err;\n}","preventionTips":["Avoid concurrent navigation, reloads, or page.close() while fetchLinuxDoJson is evaluating.","Use skipNavigate: true once navigation has settled (networkidle) to reduce mid-evaluate context churn.","Retry once on this error — it is typically transient — and lean on the CLI's metadata cache as a fallback for tags/categories.","Keep browser and automation driver versions current; older CDP stacks can drop evaluate results.","Monitor for browser crashes (memory pressure during the subcategory fan-out) and recycle pages periodically."],"tags":["linux-do","browser-automation","empty-response","transient"],"backgroundTag":"empty-browser-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}