ruvnet/ruflo · error
release download failed: HTTP
Error message
release download failed: HTTP ${response.status} for ${url} What it means
downloadPublicAsset() fetches a release asset from the meta-proxy-dist GitHub releases URL with redirect-following and a 120-second timeout; any non-OK status aborts the install with the HTTP code and full URL. This is the default public download path, distinct from the gh-CLI dev path.
Solutions
- Open the URL shown in the message — if 404, verify the tag exists on the cognitum-one/meta-proxy-dist releases page and that your ruflo version requests a published one
- Retry after a short wait for transient 5xx/proxy failures
- Behind corporate proxies, set HTTPS_PROXY/HTTP_PROXY so fetch can traverse them
- Update ruflo — version/asset naming changes are fixed in newer releases
Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight the release URL cheaply before scripting installs
const res = await fetch(`${distBase}/${tag}/${assetName}`, { method: 'HEAD' });
if (!res.ok) throw new Error(`release not reachable: HTTP ${res.status}`); Type guard
const isHttpDownloadFailure = (e: unknown): e is Error => e instanceof Error && /^release download failed: HTTP \d+/.test(e.message);
Try / catch
for (let i = 1; ; i++) {
try {
return await downloadPublicAsset(url, MAX_BYTES);
} catch (e) {
const status = isHttpDownloadFailure(e) ? Number(/HTTP (\d+)/.exec(e.message)?.[1]) : 0;
if (status === 404 || (status && status < 500)) throw e; // permanent — do not retry
if (i >= 3) throw e; // transient exhausted
await new Promise(r => setTimeout(r, 2 ** i * 500)); // 5xx/network → backoff
}
} Prevention
- Verify the release tag exists on the dist repo before scripting installs
- Set HTTPS_PROXY explicitly in corporate networks
- Distinguish 404/403 (permanent) from 5xx (transient) when adding retries
- Pin versions confirmed to be published
When it happens
Trigger: HTTP 404 — the version tag or asset filename does not exist (deleted/unpublished release, wrong pinned version); 403 — GitHub rate limiting or a blocking corporate proxy; 5xx — transient GitHub/CDN failure. All surface through this single message with the status embedded.
Common situations: Pinning a version tag that was later removed; corporate egress proxies answering 403/502 for github.com; rate limits from shared CI IPs; wrong RUFLO_PROXY_RELEASE_SOURCE override values.
Related errors
- release asset exceeds
- Could not reach the Cognitum auth service. ruflo core…
- extracted binary path failed validation
- Failed to fetch /models
- Failed to fetch manifest from
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/37466966fb4d6abf.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/proxy/release.ts:65
return `meta-proxy-${version}-${triple}.${releaseArchiveExtension(triple)}`;
}
export interface ReleaseAssets {
archiveBytes: Buffer;
archiveFilename: string;
sumsBytes: Buffer;
sigBase64: string;
}
const DEV_INSTALL_ENV = 'RUFLO_DEV_PROXY_INSTALL';
const RELEASE_SOURCE_ENV = 'RUFLO_PROXY_RELEASE_SOURCE';
const GH_REPO = 'cognitum-one/meta-proxy';
const PUBLIC_DIST_BASE = 'https://github.com/cognitum-one/meta-proxy-dist/releases/download';
const MAX_ARCHIVE_BYTES = 32 * 1024 * 1024;
async function downloadPublicAsset(url: string, maxBytes: number): Promise<Buffer> {
const response = await fetch(url, { redirect: 'follow', signal: AbortSignal.timeout(120_000) });
if (!response.ok) throw new Error(`release download failed: HTTP ${response.status} for ${url}`);
const declared = Number(response.headers.get('content-length') ?? 0);
if (declared > maxBytes) throw new Error(`release asset exceeds ${maxBytes} byte limit`);
const bytes = Buffer.from(await response.arrayBuffer());
if (bytes.length > maxBytes) throw new Error(`release asset exceeds ${maxBytes} byte limit`);
return bytes;
}
async function ghExecutor() {
// Dynamic import, not a static one: @claude-flow/security is only an
// optionalDependency of this package (see auth/security-bridge.ts for the
// same reasoning) — a static top-level import would crash module load for
// any consumer that doesn't have it installed, even ones that never touch
// this dev-only download path.
const { SafeExecutor } = await import('@claude-flow/security');
return new SafeExecutor({ allowedCommands: ['gh'], timeout: 120_000 });
}
/**View on GitHub (pinned to fa13ee4ad6)