{"record":{"id":"f7e91543e82523cd","repo":"jackwener/OpenCLI","slug":"xianyu-personal-rendered-but-no-user-identity-ext","errorCode":null,"errorMessage":"Xianyu /personal rendered but no user identity extractable — stale unb or layout drift","messagePattern":"Xianyu /personal rendered but no user identity extractable — stale unb or layout drift","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xianyu/auth.js","lineNumber":50,"sourceCode":"  `);\n  if (probe.blocked) {\n    throw new AuthRequiredError('goofish.com', 'Xianyu blocked by verification / risk control');\n  }\n  if (probe.requiresAuth) {\n    throw new AuthRequiredError('goofish.com', 'Xianyu /personal shows login prompt — anonymous');\n  }\n  const userId = probe.domUserId || unb;\n  let decodedTracknick = '';\n  if (tracknick) {\n    try {\n      decodedTracknick = JSON.parse('\"' + tracknick.replace(/\\\\/g, '\\\\\\\\') + '\"');\n    } catch {\n      decodedTracknick = tracknick;\n    }\n  }\n  const nickname = probe.domNick || decodedTracknick;\n  if (!userId && !nickname) {\n    throw new CommandExecutionError('Xianyu /personal rendered but no user identity extractable — stale unb or layout drift');\n  }\n  return { user_id: String(userId), nickname: String(nickname) };\n}\n\nregisterSiteAuthCommands({\n  site: 'xianyu',\n  domain: 'goofish.com',\n  loginUrl: 'https://www.goofish.com/login',\n  columns: ['user_id', 'nickname'],\n  quickCheck: hasXianyuIdentityCookie,\n  verify: verifyXianyuIdentity,\n  poll: async (page) => {\n    if (!await hasXianyuIdentityCookie(page)) {\n      throw new AuthRequiredError('goofish.com', 'Waiting for Xianyu unb/tracknick cookie');\n    }\n    return verifyXianyuIdentity(page);\n  },\n});","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xianyu/auth.js#L32-L68","documentation":"The /personal page rendered (not a login prompt) but neither a DOM user id nor a nickname could be extracted, meaning the identity cannot be confirmed. The library throws CommandExecutionError because the page layout changed (layout drift) or a stale unb cookie produces no matching profile data.","triggerScenarios":"verifyXianyuIdentity finds userId (domUserId or unb cookie) and nickname (domNick or decoded tracknick) both empty after the page renders.","commonSituations":"goofish.com changed its /personal DOM structure; stale/expired unb cookie kept the session half-authenticated; anti-bot rendering served a degraded page.","solutions":["Log out and back in to refresh unb/tracknick cookies","Re-run after clearing cookies and re-authenticating","Check for goofish.com layout updates and update the DOM extraction selectors in the probe script","Retry later in case of transient anti-bot rendering"],"exampleFix":"// before\nconst identity = await verifyXianyuIdentity(page); // throws on layout drift\n// after\nif (!(await hasXianyuIdentityCookie(page))) {\n  await reLogin(page);\n}\nconst identity = await verifyXianyuIdentity(page);","handlingStrategy":"retry","validationCode":"if (!(await hasXianyuIdentityCookie(page))) await reLogin(page);","typeGuard":"function hasIdentity(x) {\n  return x != null && (x.user_id || x.nickname);\n}","tryCatchPattern":"try {\n  return await verifyXianyuIdentity(page);\n} catch (e) {\n  if (/no user identity extractable/.test(e.message)) {\n    await reLogin(page); // refresh stale unb cookie\n    return verifyXianyuIdentity(page);\n  }\n  throw e;\n}","preventionTips":["Re-login when unb cookies are old","Pin/monitor goofish.com layout changes affecting /personal selectors","Log probe DOM state on failure to diagnose drift quickly"],"tags":["xianyu","layout-drift","dom-scraping"],"backgroundTag":"page-layout-drift","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}