jackwener/OpenCLI · error · CommandExecutionError
msg
Error message
msg
What it means
For any captionData.error other than the recognized 'No captions available' case, the CLI throws CommandExecutionError with the page-supplied error message (msg), which may include the list of available caption tracks. This represents a genuine fetch/parse/HTTP failure in obtaining caption info, as opposed to a legitimate empty result.
Source
Thrown at clis/youtube/transcript.js:453
available,
requestedLang: langPref || null,
langMatched: !!(langPref && track.languageCode === langPref),
langPrefixMatched: !!(langPref && track.languageCode !== langPref && track.languageCode.startsWith(langPref))
};
})()
`));
if (!segments && (!captionData || typeof captionData !== 'object' || Array.isArray(captionData))) {
throw new CommandExecutionError(`Failed to get caption info: ${typeof captionData === 'string' ? captionData : 'malformed response'}`);
}
if (captionData?.error) {
const msg = `${captionData.error}${captionData.available ? ' (available: ' + captionData.available.join(', ') + ')' : ''}`;
// "No captions available" 是合法 empty 数据条件(作者没开字幕 + YT 没自动生成),
// 与 bilibili subtitle 的 EmptyResultError 同模式。下游应按 code EMPTY_RESULT 跳过
// 重试和 softFail 计数。其它 error(HTTP / parse / 短暂空响应)仍按 fetch 失败抛。
if (captionData.error === 'No captions available for this video') {
throw new EmptyResultError('youtube transcript', '该视频没有字幕(作者未开启 + 无自动字幕)。');
}
throw new CommandExecutionError(msg);
}
if (!segments && typeof captionData?.captionUrl !== 'string') {
throw new CommandExecutionError('Malformed caption info payload');
}
// Warn if --lang was specified but not matched
if (captionData?.requestedLang && !captionData.langMatched && !captionData.langPrefixMatched) {
console.error(`Warning: --lang "${captionData.requestedLang}" not found. Using "${captionData.language}" instead. Available: ${captionData.available.join(', ')}`);
}
// Step 2: Fetch caption XML and parse segments
// Ensure caption URL requests srv3 XML format — YouTube may return empty
// responses when no explicit format is specified.
if (!segments) {
const originalCaptionUrl = captionData.captionUrl;
let captionUrl = originalCaptionUrl;
if (!/[&?]fmt=/.test(originalCaptionUrl)) {
captionUrl = originalCaptionUrl + (originalCaptionUrl.includes('?') ? '&' : '?') + 'fmt=srv3';
}
segments = normalizeSegmentsPayload(await page.evaluate(`View on GitHub (pinned to 49907e53dc)
Solutions
- Read msg — it may include available tracks or the underlying HTTP reason — and address that cause.
- Retry after a short backoff; the source comment classifies these as transient fetch failures eligible for retry.
- Verify the video is playable in the automated browser (not deleted/region-blocked).
- Update the CLI if the message indicates a page-structure mismatch.
Example fix
// before
const segments = await getSegments(videoId);
// after
const segments = await retry(() => getSegments(videoId), { retries: 2, backoffMs: 1000 }); // transient caption fetch errors only Defensive patterns
Strategy: retry
Try / catch
try {
const segments = await getSegments(videoId);
} catch (err) {
if (!(err instanceof EmptyResultError)) {
// transient fetch/parse failure per source comment — retry with backoff
await sleep(1000);
return getSegments(videoId);
}
throw err;
} Prevention
- Apply bounded retries with backoff — the CLI classifies these as transient fetch failures
- Check the message: it may list available tracks or an HTTP reason
- Verify the video is playable in the automated browser before extracting
- Avoid hammering YouTube concurrently to reduce rate-limit-triggered errors
When it happens
Trigger: `segments` where the injected caption-info script returns {error: <anything else>} — e.g. HTTP failures fetching the player response, transient empty responses, or page-side exceptions other than the no-captions sentinel.
Common situations: Rate limiting or temporary YouTube errors; network glitches in the automated browser; player API responses failing mid-SPA navigation; video unavailable/deleted pages.
Related errors
- Failed to read Upwork feed state: ${e?.message ?? e}
- Unexpected YouTube probe: ${JSON.stringify(probe)}
- String(payload.error)
- `Malformed ${source} payload`
- captured.error
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/9994650d22ccd54b.
Report an issue: GitHub.