ruvnet/ruflo · error · Error
Failed to fetch manifest from
Error message
Failed to fetch manifest from ${url}: ${res.status} ${res.statusText} What it means
The verify command fetches the signed witness manifest (verification.md.json) from raw.githubusercontent.com for the target branch (default fix/issues-may-1-3). A non-2xx HTTP response throws with the status code and reason; the surrounding handler reports 'Could not load witness manifest: ...' and exits 1. The fetch carries a 30-second abort timeout, so hangs surface as timeout aborts, not this error.
Solutions
- Confirm the branch exists and contains verification.md.json at its root on GitHub
- Skip the network: download the manifest (or copy it from a release artifact) and pass --manifest ./verification.md.json
- From the same machine, curl -I the exact URL shown in the error to distinguish 404 vs proxy vs rate-limit
- If rate-limited (403), wait and retry, or use the local-manifest path in CI
Example fix
# before ruflo verify --branch nonexistent-branch # after curl -fsSL -o verification.md.json https://raw.githubusercontent.com/ruvnet/ruflo/main/verification.md.json ruflo verify --manifest ./verification.md.json
Defensive patterns
Strategy: retry
Validate before calling
const res = await fetch(manifestUrl, { signal: AbortSignal.timeout(10_000) });
if (!res.ok) throw new Error(`manifest fetch failed: ${res.status}`);
// pre-flight the URL yourself, or skip the network entirely with --manifest <local file> Try / catch
for (const branch of ['main', 'fix/issues-may-1-3']) {
try {
witness = await fetchWitness(branch);
break;
} catch (err) {
if (err instanceof Error && err.message.includes('Failed to fetch manifest')) continue;
throw err;
}
}
if (!witness) throw new Error('fall back to: ruflo verify --manifest ./verification.md.json'); Prevention
- Pin verification to --manifest with a file fetched during CI setup, not at verify time
- curl -I the exact manifest URL when adding a new branch to prove it exists
- Treat 403 from raw.githubusercontent.com as rate limiting — back off or go local
When it happens
Trigger: Passing --branch <name> for a branch that doesn't exist or lacks verification.md.json (404); GitHub raw CDN rate-limiting (403); a corporate proxy intercepting with 407/502.
Common situations: Verifying against an old tag whose manifest was never published; CI runners behind egress filters; regions where raw.githubusercontent.com is blocked.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- Failed to fetch /models
- Failed to get analytics
- Failed to get bulk ratings
- Failed to get ratings
- fetchAgentCard: returned HTTP
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/ca39ac616f672945.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/commands/verify.ts:63
integrity: {
manifestHashAlgo: string;
manifestHash: string;
signatureAlgo: string;
publicKey: string;
signature: string;
seedDerivation: string;
};
}
const DEFAULT_MANIFEST_URL = 'https://raw.githubusercontent.com/ruvnet/ruflo/{branch}/verification.md.json';
async function fetchWitness(branch: string): Promise<Witness> {
const url = DEFAULT_MANIFEST_URL.replace('{branch}', branch);
// audit_1776853149979: bare fetch had no timeout — a hung GitHub CDN would
// pin the verify command indefinitely. 30s is generous for a sub-MB JSON.
const res = await fetch(url, { signal: AbortSignal.timeout(30000) });
if (!res.ok) {
throw new Error(`Failed to fetch manifest from ${url}: ${res.status} ${res.statusText}`);
}
return await res.json() as Witness;
}
function loadLocalWitness(localPath: string): Witness {
if (!existsSync(localPath)) {
throw new Error(`Manifest not found: ${localPath}`);
}
return JSON.parse(readFileSync(localPath, 'utf-8')) as Witness;
}
/**
* Locate the user's installed package root.
*
* The witness manifest paths are repo-relative (e.g.
* "v3/@claude-flow/cli/dist/src/mcp-tools/hooks-tools.js"). For
* end users, only the dist/ subtree ships in node_modules. We map
* the repo path → the installed equivalent by stripping theView on GitHub (pinned to fa13ee4ad6)