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

  1. 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
  2. Retry after a short wait for transient 5xx/proxy failures
  3. Behind corporate proxies, set HTTPS_PROXY/HTTP_PROXY so fetch can traverse them
  4. 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

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


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)