{"record":{"id":"a18f7b10e0feed57","repo":"jackwener/OpenCLI","slug":"app-qianwen-com-a18f7b","errorCode":null,"errorMessage":"请在浏览器里用千问 APP 扫码登录 qianwen.com 后再重试。","messagePattern":"请在浏览器里用千问 APP 扫码登录 qianwen\\.com 后再重试。","errorType":"exception","errorClass":"AuthRequiredError","httpStatus":null,"severity":"error","filePath":"clis/qwen/history.js","lineNumber":46,"sourceCode":"    navigateBefore: false,\n    args: [\n        { name: 'limit', type: 'int', default: 20, help: 'Max conversations to show (default 20, max 100)' },\n    ],\n    columns: ['Index', 'Title', 'Updated', 'Url'],\n    func: async (page, kwargs) => {\n        const limit = Number(kwargs.limit ?? 20);\n        if (!Number.isInteger(limit) || limit <= 0) {\n            throw new ArgumentError('limit must be a positive integer');\n        }\n        if (limit > 100) {\n            throw new ArgumentError('limit must be <= 100');\n        }\n        await ensureOnQianwen(page);\n        await dismissLoginModal(page);\n        await page.wait(1);\n        const result = await getSessionListFromApi(page, limit);\n        if (!result.ok) {\n            if (result.status === 401 || result.status === 403) throw authRequired();\n            if (!result.sessions.length) {\n                throw new CommandExecutionError(`Qianwen history API failed (status=${result.status}) ${result.error || ''}`.trim());\n            }\n        }\n        if (!result.sessions.length) {\n            throw new EmptyResultError('qwen history', 'No Qianwen conversations found.');\n        }\n        return result.sessions.slice(0, limit).map((s, i) => ({\n            Index: i + 1,\n            Title: s.title || '(untitled)',\n            Updated: formatDate(s.updated_at),\n            Url: `https://www.qianwen.com/chat/${s.id}`,\n        }));\n    },\n});\n","sourceCodeStart":28,"sourceCodeEnd":62,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/qwen/history.js#L28-L62","documentation":"AuthRequiredError thrown by `qwen history` when the session-list API (chat2-api.qianwen.com) responds with HTTP 401 or 403, i.e. the backend rejected the request as unauthenticated. The CLI maps those statuses directly to authRequired() (clis/qwen/history.js:50) with the standard QR-scan guidance.","triggerScenarios":"`qwen history` calls getSessionListFromApi and receives status 401 or 403 — the browser's Qianwen cookies are missing, expired, or not accepted by the API domain.","commonSituations":"Cookie expired since last run; API domain (chat2-api.qianwen.com) requires a fresher token than the web session holds; region/edge serving 403 for suspicious traffic; user cleared cookies in the shared profile.","solutions":["Log into qianwen.com via QR scan with the Qianwen APP in the automation browser, then rerun `qwen history`","Verify the API request is being sent with the correct cookies/headers (inspect getSessionListFromApi) — a missing credential header can also yield 401","Retry after a delay if 403 appears without a login wall (possible rate-limit or WAF block)","Persist the browser profile to keep auth cookies across invocations"],"exampleFix":"// before\nconst result = await getSessionListFromApi(page, limit);\nif (!result.ok && (result.status === 401 || result.status === 403)) throw authRequired();\n// after (caller)\ntry {\n  await qwenHistory(limit);\n} catch (e) {\n  if (e.code === 'AUTH_REQUIRED') {\n    await interactiveQianwenLogin();\n    await qwenHistory(limit);\n  } else throw e;\n}","handlingStrategy":"try-catch","validationCode":"const probe = await page.evaluate(() => fetch('https://chat2-api.qianwen.com/__probe', { method: 'HEAD' }).then(r => r.status).catch(() => 0));\nif (probe === 401 || probe === 403) throw new Error('Qianwen session invalid — re-login before listing history');","typeGuard":"function isUnauthorized(res) { return res && (res.status === 401 || res.status === 403); }","tryCatchPattern":"try {\n  await qwenHistory(limit);\n} catch (e) {\n  if (isAuthError(e)) { await qrRelogin(); return qwenHistory(limit); }\n  throw e;\n}","preventionTips":["Re-login whenever cookies are older than the typical Qianwen session lifetime","Persist the profile directory so auth cookies survive CLI restarts","Handle 403-without-login-wall as rate limiting and back off before retrying","Don't clear browser storage between commands in a send->history sequence"],"tags":["auth","http-401","http-403","api","qianwen"],"backgroundTag":"login-required","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}