jackwener/OpenCLI · error · CommandExecutionError

String(payload.error)

Error message

String(payload.error)

What it means

normalizeSegmentsPayload validates the unwrapped result of a browser-evaluated YouTube player caption extraction. When the browser page returns an object with an `error` field (a structured in-page failure), the CLI rethrows it as a CommandExecutionError so the caller sees the real page-side reason instead of silent null segments. It is a deliberate error-propagation bridge from browser context to CLI context.

Source

Thrown at clis/youtube/transcript.js:31

import { extractJsonAssignmentFromHtml, parseVideoId, prepareYoutubeApiPage } from './utils.js';
import { groupTranscriptSegments, formatGroupedTranscript, } from './transcript-group.js';
import { CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';

function unwrapBrowserResult(value) {
    if (value && typeof value === 'object' && 'session' in value && 'data' in value) {
        return value.data;
    }
    return value;
}

function normalizeSegmentsPayload(value, source, { allowNull = false } = {}) {
    const payload = unwrapBrowserResult(value);
    if (payload == null && allowNull)
        return null;
    if (Array.isArray(payload))
        return payload;
    if (payload && typeof payload === 'object' && payload.error) {
        throw new CommandExecutionError(String(payload.error));
    }
    throw new CommandExecutionError(`Malformed ${source} payload`);
}

function parseJson3Segments(text) {
    let data;
    try {
        data = JSON.parse(text);
    }
    catch (err) {
        throw new CommandExecutionError(`Malformed json3 timedtext response: ${err?.message || err}`);
    }
    if (!Array.isArray(data?.events)) {
        throw new CommandExecutionError('Malformed json3 timedtext response: missing events array');
    }
    const rows = [];
    for (const event of data.events) {
        const startMs = Number(event?.tStartMs || 0);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Read the thrown message — it is the page-side error text — and fix the underlying in-page extraction cause (often a DOM/player API change).
  2. Update the YouTube CLI to the latest version so the injected player-extraction script matches current YouTube markup.
  3. Verify the browser tab/daemon session is fresh (restart the browser session) to clear stale SPA state.
  4. Check the video actually has captions; if not, handle the EMPTY_RESULT path instead of retrying.

Example fix

// before
const segments = normalizeSegmentsPayload(playerResult, 'player caption extraction', { allowNull: true });
// after
try {
  const segments = normalizeSegmentsPayload(playerResult, 'player caption extraction', { allowNull: true });
} catch (err) {
  console.error('player caption extraction failed:', err.message);
  // fall back to network-capture path
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (payload && typeof payload === 'object' && !Array.isArray(payload) && payload.error) {
  // page reported an error; handle before calling the extractor
}

Type guard

function isSegmentsPayload(v) {
  return v == null || Array.isArray(v) || (typeof v === 'object' && !('error' in v));
}

Try / catch

try {
  const segments = normalizeSegmentsPayload(playerResult, 'player caption extraction', { allowNull: true });
} catch (err) {
  // err.message is the page-side error text; log and fall back to network capture
}

Prevention

When it happens

Trigger: Calling `segments` -> `normalizeSegmentsPayload(playerResult, ...)` where the in-page evaluate returned {error: "..."} — e.g. the YouTube player response lacked captionTracks or the page script caught its own failure and serialized it as an error field.

Common situations: YouTube DOM/player changes breaking the injected caption-extraction script; videos where caption data is gated (age-restricted, consent walls); stale browser tab in a shared daemon session returning a cached error object.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/762b2fab6d57b95d. Report an issue: GitHub.