{"record":{"id":"e465d78746f7e38e","repo":"jackwener/OpenCLI","slug":"http-probe-httpstatus-from-nowcoder-profile-api","errorCode":null,"errorMessage":"HTTP ${probe.httpStatus} from nowcoder profile API","messagePattern":"HTTP (.+?) from nowcoder profile API","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/nowcoder/auth.js","lineNumber":47,"sourceCode":"    const d = await r.json();\n    if (!d || !d.success || !d.data || !d.data.id) {\n      return { kind: 'auth', detail: 'nowcoder profile returned no user data (anonymous)' };\n    }\n    return { ok: true, user_id: String(d.data.id), nickname: String(d.data.nickname || '') };\n  } catch (e) {\n    return { kind: 'exception', detail: String(e && e.message || e) };\n  }\n})()`;\n\nasync function verifyNowcoderIdentity(page) {\n  if (!await hasNowcoderSessionCookie(page)) {\n    throw new AuthRequiredError('nowcoder.com', 'Nowcoder t cookie missing (anonymous)');\n  }\n  await page.goto('https://www.nowcoder.com/');\n  await page.wait(2);\n  const probe = await page.evaluate(WHOAMI_PROBE);\n  if (probe?.kind === 'auth') throw new AuthRequiredError('nowcoder.com', probe.detail);\n  if (probe?.kind === 'http') throw new CommandExecutionError(`HTTP ${probe.httpStatus} from nowcoder profile API`);\n  if (probe?.kind === 'exception') throw new CommandExecutionError(`Nowcoder whoami failed: ${probe.detail}`);\n  if (!probe?.ok) throw new CommandExecutionError(`Unexpected nowcoder probe: ${JSON.stringify(probe)}`);\n  return { user_id: probe.user_id, nickname: probe.nickname };\n}\n\nregisterSiteAuthCommands({\n  site: 'nowcoder',\n  domain: 'nowcoder.com',\n  loginUrl: 'https://www.nowcoder.com/login',\n  columns: ['user_id', 'nickname'],\n  verify: verifyNowcoderIdentity,\n  poll: async (page) => {\n    if (!await hasNowcoderSessionCookie(page)) {\n      throw new AuthRequiredError('nowcoder.com', 'Waiting for Nowcoder login');\n    }\n    return verifyNowcoderIdentity(page);\n  },\n});","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/nowcoder/auth.js#L29-L65","documentation":"When the in-page probe's fetch to https://gw-c.nowcoder.com/api/sparta/user/profile/<uid> returns a non-OK, non-401/403 status, the probe reports kind:'http' and the library throws CommandExecutionError with 'HTTP <status> from nowcoder profile API'. This signals a server/gateway problem rather than an auth problem.","triggerScenarios":"Profile API responding 429 (rate limit), 500/502/503 (gateway errors), or 404 (API path changed) while the user is logged in.","commonSituations":"Hitting the API too frequently (rate limiting); nowcoder gateway maintenance or outages; the sparta profile endpoint path being renamed after a nowcoder API update.","solutions":["Wait and retry after a delay (backoff) — 429/5xx are usually transient","Check https://www.nowcoder.com availability in a browser","If persistent 404, the endpoint changed; update WHOAMI_PROBE to the current profile API URL","Reduce call frequency to avoid rate limiting"],"exampleFix":"// before\nconst who = await verifyNowcoderIdentity(page);\n// after\nlet who;\ntry {\n  who = await verifyNowcoderIdentity(page);\n} catch (e) {\n  if (/HTTP 4\\d\\d|HTTP 5\\d\\d from nowcoder profile API/.test(e.message)) {\n    await new Promise(r => setTimeout(r, 5000));\n    who = await verifyNowcoderIdentity(page);\n  } else throw e;\n}","handlingStrategy":"retry","validationCode":"// Pre-check reachability before the authed call:\nconst res = await fetch('https://gw-c.nowcoder.com/api/sparta/health', { method: 'HEAD' }).catch(() => null);\nif (!res || res.status >= 500) throw new Error('nowcoder gateway unavailable; retry later');","typeGuard":"function isHttpProbe(p) { return p?.kind === 'http' && typeof p.httpStatus === 'number'; }","tryCatchPattern":"try {\n  return await verifyNowcoderIdentity(page);\n} catch (e) {\n  const m = e.message.match(/HTTP (\\d{3}) from nowcoder profile API/);\n  if (m && (m[1] === '429' || m[1].startsWith('5'))) {\n    await new Promise(r => setTimeout(r, 10_000));\n    return verifyNowcoderIdentity(page);\n  }\n  throw e;\n}","preventionTips":["Use exponential backoff on 429/5xx responses","Don't poll the profile API more often than needed","Monitor nowcoder status during maintenance windows","Update the probe URL if a 404 persists (endpoint moved)"],"tags":["http-error","network","rate-limit","nowcoder"],"backgroundTag":"http-5xx-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}