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
- 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).
- 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).
- Ensure the app data/bin directory is writable and has disk space.
- 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
- Don't discard the status payload: always read error/message/detail from the install result before throwing a generic string.
- Pre-install cloudflared via package manager or a manually downloaded release in restricted-network environments; the status check will then skip the download.
- Verify the app data/bin directory is writable and on a disk with free space before enabling the tunnel.
- Watch the backend logs during cloudflared_install — the frontend error alone never carries the root cause.
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.