jackwener/OpenCLI · error · CliError

API_ERROR

API_ERROR

Error message

API_ERROR

What it means

API_ERROR (HTTP variant) is thrown by yollomiPost when the server responded but with a non-ok status. The message includes the status code and any error/message detail parsed from the JSON body; the fix hint is status-specific: 401 → not logged in, 402 → out of credits, 429 → rate limited, otherwise check parameters.

Source

Thrown at clis/yollomi/utils.js:57

          body: ${JSON.stringify(bodyJson)},
        });
        const text = await res.text();
        return { ok: res.ok, status: res.status, body: text };
      } catch (err) {
        return { ok: false, status: 0, body: err.message || 'fetch failed (on ' + location.href + ')' };
      }
    })()
  `);
    if (!result || result.status === 0) {
        throw new CliError('FETCH_ERROR', `Network error: ${result?.body || 'Failed to fetch'}`, 'Make sure Chrome is logged in to https://yollomi.com and the Browser Bridge is running');
    }
    if (!result.ok) {
        let detail = result.body;
        try {
            detail = JSON.parse(result.body)?.error || JSON.parse(result.body)?.message || result.body;
        }
        catch { }
        throw new CliError('API_ERROR', `Yollomi API ${result.status}: ${detail}`, result.status === 401
            ? 'Not logged in — open Chrome, go to https://yollomi.com and log in'
            : result.status === 402
                ? 'Insufficient credits — top up at https://yollomi.com/pricing'
                : result.status === 429
                    ? 'Rate limited — wait a moment and retry'
                    : 'Check the model and parameters');
    }
    try {
        return JSON.parse(result.body);
    }
    catch {
        throw new CliError('API_ERROR', 'Invalid JSON response', 'Try again');
    }
}
/**
 * Resolve an image input: local file → base64 data URL, URL → as-is.
 */
export function resolveImageInput(input) {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Read the status in the message: 401 → log in to yollomi.com in the bridged Chrome; 402 → top up credits at yollomi.com/pricing; 429 → wait and retry with backoff
  2. For other statuses, verify the modelId and parameters against current API docs — the body detail string is included in the error
  3. Re-authenticate if the session expired, then rerun the command
  4. Add spacing/retries between calls in scripts to avoid 429

Example fix

// before
for (const p of prompts) await generate(page, p);  // 429 after burst
// after
for (const p of prompts) {
  await generate(page, p);
  await new Promise(r => setTimeout(r, 2000));  // throttle to avoid rate limit
}
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight: confirm session and credits by loading the site in the bridged page
// and only proceed when a yollomi.com session cookie exists (no login redirect).

Type guard

null

Try / catch

try {
  await yollomiPost(page, endpoint, body);
} catch (e) {
  if (e.code !== 'API_ERROR') throw e;
  const status = parseInt(e.message.match(/API (\d{3})/)?.[1] ?? '0', 10);
  if (status === 429) { await sleep(5000); return retry(); }
  if (status === 401) throw new Error('Log in to yollomi.com first');
  if (status === 402) throw new Error('Top up credits at yollomi.com/pricing');
  throw e;
}

Prevention

When it happens

Trigger: Any yollomi command using yollomiPost (generate, upscale, video, ...) where the in-page fetch returns ok=false with an HTTP status — 401 (no/expired session), 402 (insufficient credits), 429 (too many requests), 400/500 (bad params or server fault).

Common situations: Session cookie expired after long idle (401), heavy usage draining credits (402), batch scripts hammering the API (429), or unsupported modelId/parameters after an API update (400).

Related errors


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