jackwener/OpenCLI · warning · EmptyResultError
youtube transcript
Error message
youtube transcript
What it means
After all extraction strategies (player extraction, network capture, caption XML fetch) the segments command requires at least one segment. If the final segments array is empty, it throws EmptyResultError('youtube transcript') — signaling a legitimate empty transcript outcome (code EMPTY_RESULT), which downstream logic treats as skip-worthy rather than a retryable failure.
Source
Thrown at clis/youtube/transcript.js:562
// Strip inner tags (e.g. <s> in srv3 format) and decode entities
const text = decodeEntities(content.replace(/<[^>]+>/g, '')).split('\\\\n').join(' ').trim();
if (text) {
results.push({ start: startSec, end: startSec + durSec, text });
}
pos = tagEnd + endMarker.length;
}
if (results.length === 0) {
return { error: 'Parsed 0 segments from caption XML' };
}
return results;
})()
`), 'caption XML extraction');
}
if (segments.length === 0) {
throw new EmptyResultError('youtube transcript');
}
// Step 3: Fetch chapters (for grouped mode)
let chapters = [];
if (mode === 'grouped') {
try {
const chapterData = unwrapBrowserResult(await page.evaluate(`
(async () => {
const cfg = window.ytcfg?.data_ || {};
const apiKey = cfg.INNERTUBE_API_KEY;
if (!apiKey) return [];
const resp = await fetch('/youtubei/v1/next?key=' + apiKey + '&prettyPrint=false', {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
context: { client: { clientName: 'WEB', clientVersion: '2.20240101.00.00' } },
videoId: ${JSON.stringify(videoId)}View on GitHub (pinned to 49907e53dc)
Solutions
- Catch EmptyResultError and treat the video as having no transcript — skip retries and softFail counting.
- Retry later if the video is very new (auto-captions can take time to generate).
- Verify in the YouTube UI whether a CC track exists and has content.
- If empty results cluster unexpectedly, check for a CLI/YouTube schema mismatch breaking all parse paths.
Example fix
// before
const results = await transcript(videoId); // throws on empty
// after
try {
const results = await transcript(videoId);
} catch (err) {
if (err instanceof EmptyResultError) return [];
throw err;
} Defensive patterns
Strategy: try-catch
Try / catch
try {
const segments = await getSegments(videoId);
if (segments.length === 0) return []; // defensive
} catch (err) {
if (err instanceof EmptyResultError) return []; // no transcript available
throw err;
} Prevention
- Handle EmptyResultError explicitly so pipelines skip rather than fail
- Delay processing of very new videos until auto-captions are generated
- Spot-check that empty results are isolated (many at once suggests schema drift)
- Track EMPTY_RESULT codes separately from real failures in metrics
When it happens
Trigger: `segments` completes every extraction path but each yields zero rows — e.g. a caption track exists but contains no timed events, or every fallback returned empty arrays.
Common situations: Videos whose caption track is present but empty; captions that fail to yield parseable events after YouTube schema drift; auto-captions not yet generated for freshly uploaded videos.
Related errors
- 该视频没有字幕(作者未开启 + 无自动字幕)。
- nowcoder ${source}
- No images found for illustration ${row.illust_id}.
- No Semantic Scholar citations for "${args.id}" at offset ${o
- No Semantic Scholar recommendations for "${args.id}".
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/0436188b134d7712.
Report an issue: GitHub.