jackwener/OpenCLI · error · CommandExecutionError
`Failed to get caption info: ${typeof captionData === 'strin
Error message
`Failed to get caption info: ${typeof captionData === 'string' ? captionData : 'malformed response'}` What it means
Before trusting the caption info collected from the page, the segments command checks that captionData is a non-null, non-array object. If it is a string (an in-page error message) or any other malformed shape, this error reports either the string itself or 'malformed response'. It guards the boundary between the injected page script and the Node CLI.
Source
Thrown at clis/youtube/transcript.js:443
|| tracks.find(t => t.languageCode.startsWith(langPref));
}
if (!track) {
track = tracks.find(t => t.kind !== 'asr') || tracks[0];
}
return {
captionUrl: track.baseUrl,
language: track.languageCode,
kind: track.kind || 'manual',
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(', ')}`);
}View on GitHub (pinned to 49907e53dc)
Solutions
- If the message contains an in-page error string, use it to identify the page-side failure.
- Wait for the player to be fully initialized before running extraction (add page-load readiness checks).
- Update the CLI so the injected caption-info script matches current YouTube player markup.
- Retry in a fresh session; consent/cookie walls often cause the script to return error strings.
Example fix
// before
const captionData = unwrapBrowserResult(await page.evaluate(`...`));
// after
const captionData = unwrapBrowserResult(await page.evaluate(`...`));
if (typeof captionData === 'string') {
console.error('page script reported:', captionData);
} Defensive patterns
Strategy: type-guard
Validate before calling
const captionData = unwrapBrowserResult(await page.evaluate(`...`));
if (captionData == null || typeof captionData !== 'object' || Array.isArray(captionData)) {
// handle malformed/string error response before proceeding
} Type guard
function isCaptionInfo(v) {
return !!v && typeof v === 'object' && !Array.isArray(v);
} Try / catch
try {
// caption info extraction
} catch (err) {
if (err.message.startsWith('Failed to get caption info')) {
console.error('page reported:', err.message); // string payloads carry the in-page error text
}
} Prevention
- Wait for full player initialization before evaluating extraction scripts
- Complete consent/cookie flows in the automated browser first
- Log string-returning evaluates — they usually carry the real page-side error
- Update injected scripts whenever YouTube player markup changes
When it happens
Trigger: `segments` -> page.evaluate of the caption-info script returns a string (the script hit an error and returned a message) or null/undefined/array instead of the expected caption-info object.
Common situations: YouTube DOM changes breaking the captionTracks lookup script; videos with caption UI absent entirely; consent walls preventing player data; automated tab not fully loaded when evaluate runs.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- LinkedIn cookie lookup returned malformed payload
- NotebookLM RPC transport returned malformed response fields
- Twitter profile response payload is malformed
- ${context} returned a malformed result.
- Unexpected YouTube probe: ${JSON.stringify(probe)}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/f94523413992cf46.
Report an issue: GitHub.