jackwener/OpenCLI · error · CommandExecutionError

YouTube video metadata is missing playabilityReason

Error message

YouTube video metadata is missing playabilityReason

What it means

CommandExecutionError thrown during schema validation of the extracted video payload: payload.playabilityReason is not a string. Like the playabilityStatus check, this enforces the metadata contract — the library expects both a playability status and a human-readable reason string, and throws when the reason field is missing or mistyped.

Source

Thrown at clis/youtube/video.js:27

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

function requireVideoPayload(value) {
    const payload = unwrapBrowserResult(value);
    if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
        throw new CommandExecutionError('Failed to extract video metadata from page');
    }
    if (payload.error) {
        throw new CommandExecutionError(String(payload.error));
    }
    if (typeof payload.playabilityStatus !== 'string') {
        throw new CommandExecutionError('YouTube video metadata is missing playabilityStatus');
    }
    if (typeof payload.playabilityReason !== 'string') {
        throw new CommandExecutionError('YouTube video metadata is missing playabilityReason');
    }
    if (typeof payload.membersOnly !== 'boolean') {
        throw new CommandExecutionError('YouTube video metadata is missing membersOnly');
    }
    return payload;
}

cli({
    site: 'youtube',
    name: 'video',
    access: 'read',
    description: 'Get YouTube video metadata (title, views, description, etc.)',
    domain: 'www.youtube.com',
    strategy: Strategy.COOKIE,
    args: [
        { name: 'url', required: true, positional: true, help: 'YouTube video URL or video ID' },
    ],
    columns: ['field', 'value'],

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Update the library so the extractor always defaults playabilityReason to a string (e.g. '') when absent.
  2. Log the raw payload to confirm playabilityReason is genuinely missing versus mistyped.
  3. Ensure extraction targets a fully loaded watch page where playerResponse playabilityStatus/reason are populated.
  4. Retry; if persistent across videos, the extractor likely needs updating for a YouTube schema change.

Example fix

// before (page-side extraction)
reason: playerResponse?.playabilityStatus?.reason
// after
reason: playerResponse?.playabilityStatus?.reason ?? ''
Defensive patterns

Strategy: validation

Validate before calling

const payload = unwrapBrowserResult(raw);
if (!payload || typeof payload.playabilityReason !== 'string') {
  throw new Error('Invalid video payload: playabilityReason must be a string');
}

Type guard

function hasPlayabilityReason(p) {
  return p != null && typeof p === 'object' && typeof p.playabilityReason === 'string';
}

Try / catch

try {
  const info = await video(url);
} catch (e) {
  if (e.name === 'CommandExecutionError' && /playabilityReason/.test(e.message)) {
    console.error('Extractor omitted playabilityReason');
  }
  throw e;
}

Prevention

When it happens

Trigger: The in-page extraction returned an object where playabilityReason is undefined or non-string — e.g. the page script did not populate the reason (no error reason available) or YouTube changed the field location in the player response.

Common situations: Videos that play fine (no playability error) so the script omits the reason field; YouTube schema changes; extraction on unexpected page states where the reason is not generated.

Related errors


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