{"record":{"id":"cef46135b4a56978","repo":"jackwener/OpenCLI","slug":"failed-to-fetch-watch-later-make-sure-you-are-lo","errorCode":null,"errorMessage":"Failed to fetch Watch Later — make sure you are logged into YouTube","messagePattern":"Failed to fetch Watch Later — make sure you are logged into YouTube","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/youtube/watch-later.js","lineNumber":65,"sourceCode":"        let videos = extractVideos(listContents);\n\n        let contItem = listContents[listContents.length - 1];\n        while (videos.length < limit && contItem?.continuationItemRenderer && apiKey && context) {\n          const token = contItem.continuationItemRenderer?.continuationEndpoint?.continuationCommand?.token;\n          if (!token) break;\n          const contData = await fetchBrowse(apiKey, { context, continuation: token });\n          if (contData.error) break;\n          const newItems = contData.onResponseReceivedActions?.[0]?.appendContinuationItemsAction?.continuationItems || [];\n          if (!newItems.length) break;\n          videos = videos.concat(extractVideos(newItems));\n          contItem = newItems[newItems.length - 1];\n        }\n\n        return { title, stats, videos: videos.slice(0, limit) };\n      })()\n    `);\n        if (!data || typeof data !== 'object') {\n            throw new CommandExecutionError('Failed to fetch Watch Later — make sure you are logged into YouTube');\n        }\n        if (data.error) {\n            throw new CommandExecutionError(String(data.error));\n        }\n        if (!data.videos?.length) {\n            throw new EmptyResultError('youtube watch-later');\n        }\n        const statsStr = (data.stats || []).join(' | ');\n        process.stderr.write(`${data.title}  ${statsStr}\\n`);\n        return data.videos;\n    },\n});\n","sourceCodeStart":47,"sourceCodeEnd":78,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/youtube/watch-later.js#L47-L78","documentation":"Thrown when the in-browser script used by `youtube watch-later` returns null or a non-object, meaning the Watch Later playlist could not be extracted. Because the private Watch Later page requires an authenticated session, the message tells the user the most likely cause: they are not logged into YouTube in the browser session the CLI uses. The library throws this instead of silently returning an empty result so callers can distinguish auth failure from a genuinely empty playlist.","triggerScenarios":"Running `youtube watch-later` when the browser session has no valid YouTube login, the page evaluation is blocked or returns undefined (bot check, consent wall, page layout change), or the evaluation script throws and the wrapper swallows it into null.","commonSituations":"Expired YouTube session cookies; running on a headless/CI machine where no one ever logged in; YouTube consent page intercepting navigation; IP-based bot detection preventing the playlist from rendering.","solutions":["Log into YouTube in the CLI's browser session, then re-run the command.","Verify cookies are fresh — re-authenticate if the session expired.","Run with a visible browser (not fully headless) once to see whether a consent or captcha page is blocking extraction.","Update the CLI if YouTube changed the Watch Later page structure."],"exampleFix":"// before (session without login)\n$ opencli youtube watch-later\nError: Failed to fetch Watch Later — make sure you are logged into YouTube\n// after\n$ opencli youtube login   # or re-import fresh cookies\n$ opencli youtube watch-later","handlingStrategy":"try-catch","validationCode":"// Check session before invoking\nconst loggedIn = await run(['youtube', 'whoami']).catch(() => false);\nif (!loggedIn) throw new Error('Login to YouTube before fetching Watch Later');","typeGuard":"const hasData = (d) => d !== null && typeof d === 'object';","tryCatchPattern":"try {\n  const items = await run(['youtube', 'watch-later']);\n} catch (e) {\n  if (e.message.includes('logged into YouTube')) {\n    await run(['youtube', 'login']); // re-authenticate, then retry once\n  } else throw e;\n}","preventionTips":["Re-authenticate before long-running or scheduled runs","Check login state with a cheap command before playlist calls","Avoid fully headless runs on fresh profiles where consent pages block scraping","Treat this error as an auth signal and route to a login flow"],"tags":["youtube","authentication","scraping","empty-payload"],"backgroundTag":"scraper-auth-required","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}