{"record":{"id":"eb8475baa18ecdf1","repo":"jackwener/OpenCLI","slug":"authmessage","errorCode":null,"errorMessage":"${authMessage}","messagePattern":"\\$\\{authMessage\\}","errorType":"exception","errorClass":"AuthRequiredError","httpStatus":null,"severity":"error","filePath":"clis/tiktok/utils.js","lineNumber":152,"sourceCode":"    return {\n        url: parsed.toString(),\n        username: match[1],\n        videoId: match[2],\n    };\n}\n\nexport function looksTikTokAuthFailure(message) {\n    return /\\bAUTH_REQUIRED\\b|\\b(auth|captcha|login|log in|permission|unauthori[sz]ed|forbidden)\\b|HTTP\\s+(401|403)\\b/i.test(String(message || ''));\n}\n\nexport function looksTikTokUpstreamFailure(message) {\n    return /\\b(API failed|HTTP\\s+\\d+|invalid JSON|Failed to fetch|network|fetch)\\b/i.test(String(message || ''));\n}\n\nexport function throwTikTokPageContextError(error, { authMessage, emptyPattern, emptyTarget, failureMessage }) {\n    const message = getErrorMessage(error);\n    if (looksTikTokAuthFailure(message)) {\n        throw new AuthRequiredError('tiktok.com', authMessage);\n    }\n    if (looksTikTokUpstreamFailure(message)) {\n        throw new CommandExecutionError(`${failureMessage}: ${message}`);\n    }\n    if (emptyPattern.test(message)) {\n        throw new EmptyResultError(emptyTarget, message);\n    }\n    throw new CommandExecutionError(`${failureMessage}: ${message}`);\n}\n\n// Sentinels emitted by Route 1 (button-walker) IIFEs and mapped here to\n// typed errors. Keeping the strings constant in one place makes the IIFE\n// `throw new Error(...)` callsites greppable and the mapper exhaustive.\nexport const BUTTON_WALKER_SENTINELS = {\n    AUTH_REQUIRED: 'AUTH_REQUIRED',\n    BUTTON_NOT_FOUND: 'BUTTON_NOT_FOUND',\n    STATE_VERIFY_FAIL: 'STATE_VERIFY_FAIL',\n    RATE_LIMITED: 'RATE_LIMITED',","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/tiktok/utils.js#L134-L170","documentation":"throwTikTokPageContextError maps raw page-scrape failures to typed errors. When the error message matches looksTikTokAuthFailure (login/session indicators), it rethrows as AuthRequiredError for tiktok.com using the caller-supplied authMessage.","triggerScenarios":"A page-context listing call (listExploreVideos, listFollowing, listFriends, listLive, listNotifications, listUserVideos) fails and its message matches the auth-failure pattern — e.g. TikTok returned a login wall or 'not logged in' text.","commonSituations":"Expired or missing browser session/cookies; TikTok logged the automation account out; scraping from a datacenter IP triggering a login wall; stale saved session after a TikTok logout.","solutions":["Re-authenticate with tiktok.com (log in again / refresh the stored session) and retry","Verify cookies/session state the CLI relies on are present and not expired","Run a cheaper authenticated call first to confirm the session is valid","If you believe you are logged in, check the raw upstream message for a login-wall false positive"],"exampleFix":"// before\nawait cli.listFollowing(); // throws AuthRequiredError after session expiry\n// after\nawait cli.ensureTikTokLogin(); // re-establish session\nawait cli.listFollowing();","handlingStrategy":"try-catch","validationCode":"// Verify session freshness before listing calls\nconst ok = await page.evaluate(() => !document.body.innerText.includes('Log in'));","typeGuard":"const isAuthRequiredError = (e) => e instanceof AuthRequiredError || /auth|log in|login/i.test(e?.message ?? '');","tryCatchPattern":"try { await cli.listFollowing(); } catch (e) { if (e instanceof AuthRequiredError) { await reloginTikTok(); return cli.listFollowing(); } throw e; }","preventionTips":["Refresh/validate the tiktok.com session before batch jobs","Persist cookies so sessions survive restarts","Avoid datacenter IPs that trigger login walls"],"tags":["auth","session-expired","scraping"],"backgroundTag":"authentication-required","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}