{"record":{"id":"44b09793126fcce6","repo":"jackwener/OpenCLI","slug":"failed-to-parse-notifications-data","errorCode":null,"errorMessage":"Failed to parse notifications data","messagePattern":"Failed to parse notifications data","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/v2ex/notifications.js","lineNumber":68,"sourceCode":"            payload = payloadEl.textContent?.trim() || '';\n          }\n\n          // fallback to full text cleaning if no payload (e.g. for favorites/thanks)\n          let content = payload;\n          if (!content) {\n            content = text.replace(/\\\\s+/g, ' ').trim();\n            // strip out time from content if present\n            if (time && content.includes(time)) {\n              content = content.replace(time, '').trim();\n            }\n          }\n\n          return { type, content, time };\n        });\n      }\n    `);\n        if (!Array.isArray(data))\n            throw new CommandExecutionError('Failed to parse notifications data');\n        const limit = kwargs.limit || 20;\n        return data.slice(0, limit);\n    },\n});\n","sourceCodeStart":50,"sourceCodeEnd":73,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/v2ex/notifications.js#L50-L73","documentation":"After navigating to /notifications and running the in-page extraction script, the command validates that the result is an array with Array.isArray and throws CommandExecutionError('Failed to parse notifications data') otherwise. This catches evaluate results that came back undefined/null or in an unexpected shape, meaning the notifications DOM could not be scraped as expected.","triggerScenarios":"page.evaluate returns a non-array — evaluate failed outright (page navigated/closed), the /notifications page rendered something other than the expected '#Main .box .cell[id^=\"n_\"]' list (sign-in redirect, Cloudflare page, empty/changed layout), or the evaluate bridge didn't serialize the async IIFE result correctly.","commonSituations":"Session expired so V2EX redirected to signin (no .cell[id^=n_] items and unexpected result shape); Cloudflare interstitial served; V2EX changed notifications markup; script string altered so evaluate returns undefined.","solutions":["Re-login to V2EX so /notifications renders the real notification list instead of a redirect.","Visit /notifications manually in the automation browser to clear any Cloudflare challenge, then retry.","Add a readiness wait (e.g. waitForSelector for '#Main .box') before evaluate, and raise the 1500ms settle delay if the page loads slowly.","If V2EX changed its markup, update the selector '#Main .box .cell[id^=\"n_\"]' in clis/v2ex/notifications.js.","Log the raw evaluate result (OPENCLI_VERBOSE-style debug) to see what shape actually came back."],"exampleFix":"// before\nconst data = await page.evaluate(`(async () => { ... })()`);\nif (!Array.isArray(data)) throw new CommandExecutionError('Failed to parse notifications data');\n// after: wait for items to exist first\nawait page.goto('https://www.v2ex.com/notifications');\nawait page.waitForSelector('#Main .box .cell[id^=\"n_\"]', { timeout: 10000 }).catch(() => {});\nconst data = await page.evaluate(`(async () => { ... })()`);","handlingStrategy":"type-guard","validationCode":"await page.goto('https://www.v2ex.com/notifications');\nawait page.waitForSelector('#Main .box .cell[id^=\"n_\"]', { timeout: 10000 }).catch(() => {});","typeGuard":"function isNotificationArray(v) {\n  return Array.isArray(v) && v.every(x => x && typeof x === 'object' && 'type' in x && 'content' in x);\n}","tryCatchPattern":"try {\n  const rows = await runNotifications({ limit: 20 });\n} catch (e) {\n  if (/Failed to parse notifications data/.test(e.message)) {\n    // check session/login state and page markup, then retry\n  } else throw e;\n}","preventionTips":["Ensure an authenticated session before scraping /notifications (otherwise a redirect page is scraped).","Wait for notification cells to exist instead of relying on a fixed 1500ms delay.","Log the raw evaluate result when failures occur to see the actual returned shape.","Update the '#Main .box .cell[id^=\"n_\"]' selector if V2EX changes its notifications markup."],"tags":["scraping","dom-parsing","browser-automation"],"backgroundTag":"scrape-result-shape-mismatch","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}