{"record":{"id":"5b6921b2dd38eaa8","repo":"jackwener/OpenCLI","slug":"xueqiu-com","errorCode":null,"errorMessage":"xueqiu.com","messagePattern":"xueqiu\\.com","errorType":"exception","errorClass":"AuthRequiredError","httpStatus":null,"severity":"critical","filePath":"clis/xueqiu/auth.js","lineNumber":11,"sourceCode":"import { AuthRequiredError, CommandExecutionError } from '@jackwener/opencli/errors';\nimport { registerSiteAuthCommands } from '../_shared/site-auth.js';\n\nasync function hasXueqiuAccessToken(page) {\n  const cookies = await page.getCookies({ url: 'https://xueqiu.com' });\n  return cookies.some(c => c.name === 'xq_a_token' && c.value);\n}\n\nasync function verifyXueqiuIdentity(page) {\n  if (!await hasXueqiuAccessToken(page)) {\n    throw new AuthRequiredError('xueqiu.com', 'Xueqiu xq_a_token cookie missing — anonymous');\n  }\n  await page.goto('https://xueqiu.com/');\n  await page.wait(2);\n  const probe = await page.evaluate(`(async () => {\n    try {\n      const res = await fetch(\n        'https://stock.xueqiu.com/v5/stock/portfolio/stock/list.json?size=1&category=1&pid=-1',\n        { credentials: 'include' },\n      );\n      if (res.status === 403) {\n        return { kind: 'http', httpStatus: 403, detail: 'xueqiu stock API 403 — anti-bot / rate limit' };\n      }\n      if (!res.ok) return { kind: 'http', httpStatus: res.status };\n      const d = await res.json();\n      if (d?.error_code === 60201) {\n        return { kind: 'auth', detail: 'xueqiu portfolio API error_code 60201 用户id无效 — anonymous' };\n      }\n      if (d?.error_code) {","sourceCodeStart":1,"sourceCodeEnd":29,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xueqiu/auth.js#L1-L29","documentation":"verifyXueqiuIdentity first checks via hasXueqiuAccessToken that the browser session has a non-empty `xq_a_token` cookie for xueqiu.com. If absent, it throws AuthRequiredError('xueqiu.com', 'Xueqiu xq_a_token cookie missing — anonymous'), meaning the session is anonymous and xueqiu APIs will reject or degrade requests.","triggerScenarios":"Running the auth flow in a browser context that was never logged into xueqiu.com, after cookies were cleared/expired, with a profile pointing at the wrong user-data dir, or when cookie retrieval is scoped to the wrong URL so the token isn't visible.","commonSituations":"Fresh automation profiles, token expiry after xueqiu rotates xq_a_token, headless sessions where login was never completed, or corporate proxies stripping cookies.","solutions":["Log in to xueqiu.com in the automated browser session to obtain xq_a_token","Point the tool at the browser profile that already holds the cookie","Clear and redo the login flow so cookies are freshly set","Verify getCookies({url:'https://xueqiu.com'}) actually returns the cookie (domain/path scoping)"],"exampleFix":"// before (anonymous session)\nawait page.getCookies({ url: 'https://xueqiu.com' }); // no xq_a_token -> throw\n// after\nawait page.login('xueqiu.com'); // complete login first\nawait page.getCookies({ url: 'https://xueqiu.com' }); // xq_a_token present","handlingStrategy":"validation","validationCode":"const cookies = await page.getCookies({ url: 'https://xueqiu.com' });\nif (!cookies.some(c => c.name === 'xq_a_token' && c.value)) throw new Error('Login to xueqiu.com first: xq_a_token missing');","typeGuard":"const hasXqToken = (cookies) => Array.isArray(cookies) && cookies.some(c => c.name === 'xq_a_token' && Boolean(c.value));","tryCatchPattern":"try { await verifyXueqiuIdentity(page); } catch (e) { if (String(e).includes('xq_a_token')) { console.error('Run the xueqiu login flow, then retry'); process.exitCode = 1; } else throw e; }","preventionTips":["Always run the login flow before authenticated xueqiu commands","Verify the xq_a_token cookie exists before API probes","Use a persistent browser profile so cookies survive restarts","Re-check cookies after long idle periods (expiry)"],"tags":["auth","cookies","xueqiu"],"backgroundTag":"missing-auth-cookie","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}