{"record":{"id":"a908d3f65aadebff","repo":"jackwener/OpenCLI","slug":"probe-detail-a908d3","errorCode":null,"errorMessage":"${probe.detail}","messagePattern":"\\$\\{probe\\.detail\\}","errorType":"exception","errorClass":"AuthRequiredError","httpStatus":null,"severity":"error","filePath":"clis/toutiao/auth.js","lineNumber":52,"sourceCode":"          }\n          for (const v of Object.values(node)) if (v && typeof v === 'object') stack.push(v);\n        }\n      } catch {}\n      if (!userId) {\n        const ssoUid = (document.cookie.split('; ').find(c => c.startsWith('sso_uid=')) || '').split('=')[1] || '';\n        if (ssoUid) userId = ssoUid;\n      }\n      if (!nickname) {\n        const el = document.querySelector('.user-name, .header-username, .avatar-name, [class*=\"userName\"]');\n        nickname = (el?.innerText || '').trim();\n      }\n      if (!userId) {\n        return { kind: 'auth', detail: 'Toutiao dashboard rendered but no user_id surface — stale session' };\n      }\n      return { ok: true, user_id: userId, nickname };\n    })()\n  `);\n  if (probe?.kind === 'auth') throw new AuthRequiredError('toutiao.com', probe.detail);\n  if (!probe?.ok) throw new CommandExecutionError(`Unexpected Toutiao probe: ${JSON.stringify(probe)}`);\n  return { user_id: probe.user_id, nickname: probe.nickname };\n}\n\nregisterSiteAuthCommands({\n  site: 'toutiao',\n  domain: 'toutiao.com',\n  loginUrl: 'https://mp.toutiao.com/auth/page/login',\n  columns: ['user_id', 'nickname'],\n  quickCheck: hasToutiaoSessionCookie,\n  verify: verifyToutiaoIdentity,\n  poll: async (page) => {\n    if (!await hasToutiaoSessionCookie(page)) {\n      throw new AuthRequiredError('toutiao.com', 'Waiting for Toutiao sessionid cookie');\n    }\n    return verifyToutiaoIdentity(page);\n  },\n});","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/toutiao/auth.js#L34-L70","documentation":"AuthRequiredError rethrown from verifyToutiaoIdentity when the in-page probe returns {kind:'auth'}. Either mp.toutiao.com redirected to /auth/page/login (anonymous) or the dashboard rendered but no user_id could be extracted from __INITIAL_STATE__/__REDUX_STATE__/__SSR_DATA__, the sso_uid cookie, or DOM selectors — interpreted as an anonymous or stale session.","triggerScenarios":"Calling toutiao auth verify (or the poll path after the sessionid cookie exists) when: the URL matches /auth/page/login despite a sessionid cookie, or the probe finds no user_id in any state/cookie/DOM surface — typically an expired or invalidated session.","commonSituations":"Server-side session invalidated (logged in elsewhere, password change, TTL expiry) while the old sessionid cookie remains stored; Toutiao layout/A-B change renaming state keys and selectors so the probe can't find user info; anti-bot or error page served instead of the dashboard.","solutions":["Log in again at https://mp.toutiao.com/auth/page/login — a present-but-stale sessionid cookie is the most common cause — then re-run verify.","Confirm manually in the same browser profile that mp.toutiao.com shows the dashboard without redirecting to login.","Clear mp.toutiao.com cookies and do a fresh login so no stale sessionid remains.","If the dashboard renders fine for a human but the probe still finds no user_id, update the probe's state keys/selectors in clis/toutiao/auth.js to the current site layout.","Wait a moment after login completes before verifying; a redirect race right after login can trigger this transiently."],"exampleFix":"// before: stale cookie makes the probe return {kind:'auth'}\nawait toutiaoAuthVerify(page); // AuthRequiredError: stale session\n// after: force a fresh login when verify reports auth\ntry {\n  await toutiaoAuthVerify(page);\n} catch (e) {\n  if (e.name === 'AuthRequiredError') {\n    await clearCookies(page, 'mp.toutiao.com');\n    await toutiaoLogin(page);\n    await toutiaoAuthVerify(page);\n  } else throw e;\n}","handlingStrategy":"try-catch","validationCode":"const cookies = await page.getCookies({ url: 'https://mp.toutiao.com' });\nif (!cookies.some(c => c.name === 'sessionid' && c.value)) {\n  throw new Error('sessionid missing — do a fresh login before verify');\n}\nfunction isValidToutiaoIdentity(id) {\n  return !!id && typeof id.user_id === 'string' && id.user_id.length > 0;\n}","typeGuard":"function isAuthProbeResult(probe) {\n  return !!probe && typeof probe === 'object' && probe.kind === 'auth' && typeof probe.detail === 'string';\n}","tryCatchPattern":"try {\n  const identity = await toutiaoAuthVerify(page);\n} catch (err) {\n  if (err.name === 'AuthRequiredError') { // redirect-to-login or stale-session detail\n    await clearSiteCookies(page, 'mp.toutiao.com');\n    await toutiaoAuthLogin(page);\n    return toutiaoAuthVerify(page);\n  }\n  throw err;\n}","preventionTips":["Treat any AuthRequiredError from verify as 're-login required' and automate a fresh login (clear cookies first to drop the stale sessionid).","Re-verify the session at the start of every run; it can be invalidated server-side at any time.","Avoid concurrent logins to the same Toutiao account, which can invalidate the cookie.","When Toutiao redesigns its dashboard, update the probe's state keys and DOM selectors in clis/toutiao/auth.js.","Add a short settle wait after login completes before verifying to avoid redirect races."],"tags":["auth","stale-session","browser-automation","toutiao"],"backgroundTag":"session-expired","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}