{"record":{"id":"1903516e31f88a73","repo":"jackwener/OpenCLI","slug":"outcome-detail-label-returned-http-out","errorCode":null,"errorMessage":"${outcome?.detail || `${label} returned HTTP ${outcome?.status}`}","messagePattern":"(.+?) returned HTTP (.+?)`\\}","errorType":"exception","errorClass":"AuthRequiredError('web.okjike.com')","httpStatus":null,"severity":"error","filePath":"clis/jike/utils.js","lineNumber":76,"sourceCode":"      const response = await fetch(${JSON.stringify(url)}, {\n        method: 'POST',\n        credentials: 'include',\n        headers,\n        body: JSON.stringify(${JSON.stringify(requestBody)}),\n      });\n      let body;\n      try {\n        body = await response.json();\n      } catch (error) {\n        return { kind: 'json', status: response.status, detail: String(error?.message || error) };\n      }\n      return { kind: 'response', status: response.status, body };\n    } catch (error) {\n      return { kind: 'transport', detail: String(error?.message || error) };\n    }\n  })()`);\n  if (outcome?.kind === 'auth' || outcome?.status === 401 || outcome?.status === 403) {\n    throw new AuthRequiredError('web.okjike.com', outcome?.detail || `${label} returned HTTP ${outcome?.status}`);\n  }\n  if (outcome?.kind === 'transport') {\n    throw new CommandExecutionError(`${label} request failed: ${outcome.detail}`);\n  }\n  if (outcome?.kind === 'json') {\n    throw new CommandExecutionError(`${label} returned invalid JSON: ${outcome.detail}`);\n  }\n  if (outcome?.kind !== 'response' || !Number.isInteger(outcome.status)) {\n    throw new CommandExecutionError(`${label} returned an unexpected response`);\n  }\n  if (outcome.status < 200 || outcome.status >= 300) {\n    throw new CommandExecutionError(`${label} returned HTTP ${outcome.status}`);\n  }\n  return outcome.body;\n}\n\n/**\n * 注入浏览器 evaluate 的 JS 函数字符串。","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/jike/utils.js#L58-L94","documentation":"AuthRequiredError for web.okjike.com thrown by postJikeApi when the POST outcome indicates auth failure: the probe returned kind 'auth' (missing JK_ACCESS_TOKEN) or the API responded with HTTP 401/403. The detail message is the probe detail, or falls back to '<label> returned HTTP <status>'.","triggerScenarios":"Calling any Jike command that goes through postJikeApi while logged out (no JK_ACCESS_TOKEN in localStorage) or with an expired/revoked token rejected as 401/403 by api.ruguoapp.com.","commonSituations":"Token expired after session rotation; Jike invalidated the device/token server-side; localStorage cleared between runs; running the command from a browser context that never completed login.","solutions":["Log into web.okjike.com in the driven browser and retry","Confirm JK_ACCESS_TOKEN exists in localStorage on web.okjike.com; re-login if missing","If 401/403 persists with a token present, log out/in to obtain a fresh token","Use a persistent browser profile so the session is retained across CLI runs"],"exampleFix":"// before: expired token\nawait postJikeApi(page, '/1.0/comment', body, 'comment'); // AuthRequiredError\n// after: refresh session first\nawait loginJike(page); // re-authenticates and stores fresh JK_ACCESS_TOKEN\nawait postJikeApi(page, '/1.0/comment', body, 'comment');","handlingStrategy":"try-catch","validationCode":"const token = localStorage.getItem('JK_ACCESS_TOKEN');\nif (!token) throw new Error('JK_ACCESS_TOKEN missing — log into web.okjike.com first');","typeGuard":"function isAuthError(e) { return e && e.name === 'AuthRequiredError'; }","tryCatchPattern":"try {\n  const body = await postJikeApi(page, '/1.0/comment', payload, 'comment');\n} catch (e) {\n  if (isAuthError(e)) {\n    await loginJike(page); // refresh token\n    return postJikeApi(page, '/1.0/comment', payload, 'comment');\n  }\n  throw e;\n}","preventionTips":["Keep the browser session logged in before making POST calls","Persist a dedicated browser profile for the CLI","Re-authenticate when 401/403 recurs with an existing token","Avoid clearing site data between runs"],"tags":["authentication","jike","http-401"],"backgroundTag":"auth-required","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}