lbjlaq/Antigravity-Manager · error · Error

Cloudflared install failed

Error message

Cloudflared install failed

What it means

handleCfToggle() in src/pages/ApiProxy.tsx:301 throws this when invoke('cloudflared_install') resolves successfully but the returned status object still has installed: false — i.e. the backend ran the install routine and reported failure without throwing (errors inside the install flow are folded into the status). In web mode this maps to POST /api/proxy/cloudflared/install (request.ts:103). The frontend then discards whatever reason the status carried and throws a bare string, losing the diagnostic.

Source

Thrown at src/pages/ApiProxy.tsx:301

    };

    // Cloudflared: 启动/停止
    const handleCfToggle = async (enable: boolean) => {
        if (enable && !status.running) {
            showToast(
                t('proxy.cloudflared.require_proxy_running', { defaultValue: 'Please start the local proxy service first' }),
                'warning'
            );
            return;
        }
        setCfLoading(true);
        try {
            if (enable) {
                if (!cfStatus.installed) {
                    const installStatus = await invoke<typeof cfStatus>('cloudflared_install');
                    setCfStatus(installStatus);
                    if (!installStatus.installed) {
                        throw new Error('Cloudflared install failed');
                    }
                    showToast(t('proxy.cloudflared.install_success', { defaultValue: 'Cloudflared installed successfully' }), 'success');
                }

                const config = {
                    enabled: true,
                    mode: cfMode,
                    port: appConfig?.proxy.port || 8045,
                    token: cfMode === 'auth' ? cfToken : null,
                    use_http2: cfUseHttp2,
                };
                const status = await invoke<typeof cfStatus>('cloudflared_start', { config });
                setCfStatus(status);
                showToast(t('proxy.cloudflared.started', { defaultValue: 'Tunnel started' }), 'success');

                // 持久化“启用”状态
                if (appConfig) {
                    const newConfig = {

View on GitHub (pinned to a2e3c45423)

Solutions

  1. Inspect the actual installStatus object (log it) and the backend logs — it typically carries an error/message/detail field naming the real cause (network, permission, arch).
  2. Fix network reachability for the download host (configure system proxy, or pre-download the cloudflared binary for your OS/arch and place it where the manager looks for it, then re-toggle).
  3. Ensure the app data/bin directory is writable and has disk space.
  4. As a workaround, install cloudflared manually (package manager or GitHub release), then press install/refresh status again so cloudflared_get_status detects the existing binary.

Example fix

// before
const installStatus = await invoke<typeof cfStatus>('cloudflared_install');
setCfStatus(installStatus);
if (!installStatus.installed) {
    throw new Error('Cloudflared install failed');
}

// after: keep the backend's reason instead of a bare string
if (!installStatus.installed) {
    const reason = (installStatus as any).error || (installStatus as any).message || 'unknown reason (check network / GitHub reachability / write permissions)';
    throw new Error(`Cloudflared install failed: ${reason}`);
}
Defensive patterns

Strategy: retry

Validate before calling

// Check status fields before treating the install as a hard failure
const installStatus = await invoke<Record<string, unknown>>('cloudflared_install');
const reason = (installStatus.error ?? installStatus.message ?? installStatus.detail) as string | undefined;
const transient = typeof reason === 'string' && /timeout|network|temporarily/i.test(reason);
if (!installStatus.installed && transient) {
  // one retry is reasonable for flaky downloads; surface reason otherwise
}

Type guard

type CloudflaredStatus = { installed: boolean; error?: string; message?: string; detail?: string };
const isInstallFailure = (s: unknown): s is CloudflaredStatus & { installed: false } =>
  typeof s === 'object' && s !== null && (s as CloudflaredStatus).installed !== true;

Try / catch

let installStatus = await invoke('cloudflared_install');
if (!installStatus.installed) {
  const reason = installStatus.error || installStatus.message || 'check network / GitHub reachability';
  if (/timeout|network|temporarily/i.test(String(reason))) {
    await new Promise(r => setTimeout(r, 2000));
    installStatus = await invoke('cloudflared_install'); // single retry for transient download failure
  }
  if (!installStatus.installed) throw new Error(`Cloudflared install failed: ${reason}`);
}

Prevention

When it happens

Trigger: The backend cannot download the cloudflared binary (GitHub releases unreachable, GFW/firewall block, proxy needed but not configured); no write permission in the data/bin directory; unsupported OS/arch with no matching release artifact; checksum verification failure or partial download; disk full. Also any server-side install error that the manager converts into { installed: false, ... } instead of an HTTP error.

Common situations: Enabling the Cloudflare tunnel from behind a corporate firewall or in mainland China where github.com is slow/blocked; read-only or sandboxed app directory; CI/container environments without the build tools or permissions cloudflared's installer expects; toggling the tunnel on a fresh machine where cfStatus.installed is false so the implicit install runs first.

Related errors


AI-assisted analysis of lbjlaq/Antigravity-Manager@a2e3c45423 (2026-08-16). Data as JSON: /api/errors/29ff6637a710645f. Report an issue: GitHub.