ruvnet/ruflo · error
peer url must be http or https
Error message
peer url must be http or https
What it means
validatePeerUrl allows only http: and https: protocols. Other schemes (file:, ftp:, ws:, data:, etc.) are rejected, explicitly to prevent a peer entry from becoming a local file read via file:. The check runs after the URL successfully parses.
Solutions
- Use an http:// or https:// URL for the peer endpoint
- If the peer serves another protocol, expose/proxy it behind an HTTP(S) endpoint registered in the federation
- Remove any file:// paths from peer configuration and supply a real network address
- If this was an internal test, run an HTTP server locally and register http://127.0.0.1:port instead
Example fix
// before
validatePeerUrl('file:///var/lib/peer.json');
// after
validatePeerUrl('https://peer.example.com'); Defensive patterns
Strategy: validation
Validate before calling
const u = new URL(peerUrl);
if (u.protocol !== 'http:' && u.protocol !== 'https:') {
throw new Error(`peer url scheme must be http/https, got '${u.protocol}'`);
} Try / catch
try {
const origin = validatePeerUrl(rawUrl);
} catch (e) {
if (e.message === 'peer url must be http or https') {
console.error(`Refusing non-HTTP peer endpoint '${rawUrl}' — use http(s) or an HTTP proxy`);
} else throw e;
} Prevention
- Never use file:// or ws:// strings in peer URL fields
- Proxy non-HTTP services behind an HTTPS endpoint before registering them
- Validate scheme at config-load time, before any addPeer call
- Treat file:-scheme peer entries as a security smell — the library blocks them deliberately
When it happens
Trigger: Calling validatePeerUrl(raw) or addPeer(...) with a parseable URL whose u.protocol is not 'http:' or 'https:' — e.g. 'file:///etc/passwd', 'ftp://host/x', 'ws://host:9000'.
Common situations: Reusing an internal WebSocket/FTP endpoint string as a peer URL; pointing a peer at a local file path for testing; copy-pasting a ws:// service URL from another config.
Understand the failure class
Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.
Related errors
- FORBIDDEN_PROTOCOL
- basePath contains disallowed characters
- Command not allowed
- Dangerous key segment rejected
- EMPTY_PREFIXES
AI-assisted analysis of ruvnet/ruflo@2602b642d9 (2026-09-15).
Data as JSON: /api/errors/b24caf7f2cbc1c5c.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/mcp-tools/agentbbs-federation.ts:254
}
}
function writePeers(basePath: string, peers: FederationPeer[]): void {
ensureDir(basePath);
writeFileSync(peersPath(basePath), JSON.stringify(peers, null, 2) + '\n');
}
/**
* Reject anything that is not a plain http(s) URL to a host.
*
* Blocks credentials-in-URL (they would be logged), and non-http schemes such
* as `file:` which would turn a peer entry into a local file read.
*/
export function validatePeerUrl(raw: string): string {
let u: URL;
try { u = new URL(raw); } catch { throw new Error('peer url is not a valid URL'); }
if (u.protocol !== 'http:' && u.protocol !== 'https:') {
throw new Error('peer url must be http or https');
}
if (u.username || u.password) throw new Error('peer url must not embed credentials');
return u.origin;
}
export function addPeer(
basePath: string,
input: { nodeId: string; url: string; publicKey: string; label?: string },
): FederationPeer {
if (!NODE_ID_RE.test(input.nodeId ?? '')) throw new Error('nodeId must be 16 lowercase hex chars');
if (!HEX64_RE.test(input.publicKey ?? '')) throw new Error('publicKey must be 64 lowercase hex chars');
const url = validatePeerUrl(String(input.url));
const peers = readPeers(basePath);
if (peers.length >= MAX_PEERS) throw new Error(`peer registry is full (${MAX_PEERS})`);
const existing = peers.find(p => p.nodeId === input.nodeId);
if (existing) {View on GitHub (pinned to 2602b642d9)