jackwener/OpenCLI · error · CommandExecutionError

${failureMessage}: ${message}

Error message

${failureMessage}: ${message}

What it means

When the underlying error message matches looksTikTokUpstreamFailure (API failed / HTTP <code> / invalid JSON / Failed to fetch / network), the mapper wraps it in CommandExecutionError as '<failureMessage>: <message>'.

Source

Thrown at clis/tiktok/utils.js:155

        videoId: match[2],
    };
}

export function looksTikTokAuthFailure(message) {
    return /\bAUTH_REQUIRED\b|\b(auth|captcha|login|log in|permission|unauthori[sz]ed|forbidden)\b|HTTP\s+(401|403)\b/i.test(String(message || ''));
}

export function looksTikTokUpstreamFailure(message) {
    return /\b(API failed|HTTP\s+\d+|invalid JSON|Failed to fetch|network|fetch)\b/i.test(String(message || ''));
}

export function throwTikTokPageContextError(error, { authMessage, emptyPattern, emptyTarget, failureMessage }) {
    const message = getErrorMessage(error);
    if (looksTikTokAuthFailure(message)) {
        throw new AuthRequiredError('tiktok.com', authMessage);
    }
    if (looksTikTokUpstreamFailure(message)) {
        throw new CommandExecutionError(`${failureMessage}: ${message}`);
    }
    if (emptyPattern.test(message)) {
        throw new EmptyResultError(emptyTarget, message);
    }
    throw new CommandExecutionError(`${failureMessage}: ${message}`);
}

// Sentinels emitted by Route 1 (button-walker) IIFEs and mapped here to
// typed errors. Keeping the strings constant in one place makes the IIFE
// `throw new Error(...)` callsites greppable and the mapper exhaustive.
export const BUTTON_WALKER_SENTINELS = {
    AUTH_REQUIRED: 'AUTH_REQUIRED',
    BUTTON_NOT_FOUND: 'BUTTON_NOT_FOUND',
    STATE_VERIFY_FAIL: 'STATE_VERIFY_FAIL',
    RATE_LIMITED: 'RATE_LIMITED',
};

// Retryability for write-class typed errors. Captured in the hint string

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry after a delay — upstream failures are often transient rate limits
  2. Inspect the embedded upstream message for the HTTP status and address it (429 => back off longer)
  3. Check network/proxy reachability of tiktok.com (curl -I https://www.tiktok.com)
  4. Update the CLI if invalid JSON persists — TikTok may have changed its response format

Example fix

// before
await cli.listLive();
// after
try { await cli.listLive(); }
catch (e) {
  if (/rate|429/i.test(e.message)) await sleep(60_000);
  await cli.listLive();
}
Defensive patterns

Strategy: retry

Validate before calling

// Pre-check connectivity
await fetch('https://www.tiktok.com', { method: 'HEAD' });

Type guard

const isUpstreamFailure = (e) => /\b(API failed|HTTP\s+\d+|invalid JSON|Failed to fetch|network|fetch)\b/i.test(e?.message ?? '');

Try / catch

try { return await cli.listExploreVideos(); } catch (e) { if (isUpstreamFailure(e) && attempts < 3) { await backoff(attempts); return retry(); } throw e; }

Prevention

When it happens

Trigger: Any of the page-context listing commands hits an upstream fetch failure: TikTok API returned an HTTP error, response was invalid JSON, or the in-page fetch threw a network error.

Common situations: TikTok rate-limiting or 5xx responses; corporate proxy blocking tiktok.com; flaky network/DNS during scraping; TikTok changing an internal API response shape (invalid JSON).

Related errors


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