{"record":{"id":"3cfb60e950862cb9","repo":"jackwener/OpenCLI","slug":"captured-error","errorCode":null,"errorMessage":"captured.error","messagePattern":"captured\\.error","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/youtube/transcript.js","lineNumber":384,"sourceCode":"            const parsed = parseJson3(text);\n            if (parsed.error) return { error: parsed.error };\n            if (parsed.rows.length > 0) return parsed.rows;\n          }\n\n          return null;\n        } finally {\n          try { player?.pauseVideo?.(); } catch {}\n          if (originalFetch) globalThis.fetch = originalFetch;\n          if (OriginalXHR) globalThis.XMLHttpRequest = OriginalXHR;\n        }\n      })()\n    `);\n        let segments = normalizeSegmentsPayload(playerResult, 'player caption extraction', { allowNull: true });\n        if (!segments && canCapture) {\n            try {\n                const captured = extractSegmentsFromNetworkCapture(await page.readNetworkCapture(), lang, videoId);\n                if (captured.error) {\n                    throw new CommandExecutionError(captured.error);\n                }\n                if (captured.segments.length > 0) {\n                    segments = captured.segments;\n                }\n            }\n            catch (err) {\n                if (err instanceof CommandExecutionError)\n                    throw err;\n                // Keep existing fallback path when capture is unavailable.\n            }\n        }\n        if (!segments) {\n            await prepareYoutubeApiPage(page);\n        }\n        // Fallback: get caption track URL from watch page HTML\n        const captionData = segments ? null : unwrapBrowserResult(await page.evaluate(`\n      (async () => {\n        const extractJsonAssignmentFromHtml = ${extractJsonAssignmentFromHtml.toString()};","sourceCodeStart":366,"sourceCodeEnd":402,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/youtube/transcript.js#L366-L402","documentation":"In the segments command, after the player-extraction path fails, the CLI falls back to extractSegmentsFromNetworkCapture over the browser's network capture. If that function returns {error}, the error is thrown as a CommandExecutionError. The capture path reports an error when captured timedtext entries exist but none could be parsed into segments.","triggerScenarios":"`segments` -> fallback path where page.readNetworkCapture() contains timedtext entries matching lang/video, but parseJson3Segments fails on every responsePreview, so extractSegmentsFromNetworkCapture returns {error: '...'} which is rethrown.","commonSituations":"Stale signed timedtext URLs in the daemon-shared tab returning error bodies; YouTube serving bot-check HTML in captured timedtext responses; SPA navigation leaving captures from prior videos that pass URL filtering but have expired pot tokens.","solutions":["Restart the browser session to clear stale network captures, then reload the video page so fresh timedtext requests are captured.","Check the embedded captured.error message for the underlying parse failure cause.","Ensure consent/bot checks passed in the automated tab before the timedtext request fires.","Update the CLI if YouTube changed the timedtext response format or pot token requirements."],"exampleFix":"// before\nconst captured = extractSegmentsFromNetworkCapture(await page.readNetworkCapture(), lang, videoId);\nif (captured.error) throw new CommandExecutionError(captured.error);\n// after\nconst captured = extractSegmentsFromNetworkCapture(await page.readNetworkCapture(), lang, videoId);\nif (captured.error) {\n  console.error('network capture fallback failed:', captured.error);\n  // trigger a fresh page reload to recapture timedtext\n}","handlingStrategy":"fallback","validationCode":"const capture = await page.readNetworkCapture();\nconst hasTimedtext = Array.isArray(capture) && capture.some(e => String(e?.url || '').includes('/api/timedtext'));\nif (!hasTimedtext) {\n  // nothing captured yet; reload the page before using the fallback path\n}","typeGuard":"function isCaptureResult(v) {\n  return !!v && typeof v === 'object' && (Array.isArray(v.segments) || typeof v.error === 'string');\n}","tryCatchPattern":"try {\n  const captured = extractSegmentsFromNetworkCapture(await page.readNetworkCapture(), lang, videoId);\n  if (captured.error) throw new Error(captured.error);\n} catch (err) {\n  console.error('capture fallback failed:', err.message);\n  // reload page and recapture fresh timedtext responses\n}","preventionTips":["Restart browser sessions to clear stale daemon-shared network captures","Reload the video page so fresh pot-signed timedtext requests are captured","Verify video/lang scoping filters are intact in your CLI version","Keep the CLI updated for pot token / timedtext format changes"],"tags":["youtube","network-capture","browser-automation","timedtext"],"backgroundTag":"stale-network-capture","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}