ruvnet/ruflo · error
peer url is not a valid URL
Error message
peer url is not a valid URL
What it means
validatePeerUrl rejects peer URLs that the URL constructor cannot parse at all. The library requires each federation peer entry to carry a syntactically valid absolute URL, since the value is later used as a network endpoint. Malformed strings are refused at registration time rather than failing later during requests.
Solutions
- Include the full absolute URL with scheme, e.g. 'https://peer.example.com:8080'
- Trim whitespace and remove stray quotes/characters from the configured URL
- Validate with new URL(raw) in the caller before persisting peer config
- Check the config source (env var, JSON, YAML) isn't truncating or interpolating the value incorrectly
Example fix
// before
addPeer(base, { nodeId: '0a1b2c3d4e5f6071', url: 'peer.example.com', publicKey: PK });
// after
addPeer(base, { nodeId: '0a1b2c3d4e5f6071', url: 'https://peer.example.com', publicKey: PK }); Defensive patterns
Strategy: validation
Validate before calling
function isParsableUrl(raw: string): boolean {
try { new URL(raw); return true; } catch { return false; }
}
if (!isParsableUrl(peerUrl)) throw new Error(`peer url must be an absolute URL with scheme: ${peerUrl}`); Type guard
function isHttpUrl(raw: string): raw is string {
try { const u = new URL(raw); return u.protocol === 'http:' || u.protocol === 'https:'; } catch { return false; }
} Try / catch
try {
const origin = validatePeerUrl(rawUrl);
} catch (e) {
if (/peer url/.test(e.message)) {
console.error(`Invalid peer URL '${rawUrl}': ${e.message}`);
// prompt user / abort registration
} else throw e;
} Prevention
- Always include the scheme (https://) in peer config values
- Trim and quote-check values read from env vars, YAML, or CLI args
- Run validatePeerUrl in a config lint step before startup
- Never construct peer URLs by string concatenation without validating the result
When it happens
Trigger: Calling validatePeerUrl(raw) or addPeer(basePath, {..., url: raw}) with a string for which new URL(raw) throws — e.g. 'peer.example.com' (no scheme), 'http://' (empty host), 'not a url', or an empty string.
Common situations: Config files where the scheme was omitted; templated URLs left with an unfilled placeholder; trailing spaces or stray characters pasted into a peer list; YAML/JSON values coerced from numbers.
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
- INVALID_URL
- peer url must be http or https
- actualUsd must be a non-negative finite number
- Agent config must include id, name, and type
AI-assisted analysis of ruvnet/ruflo@2602b642d9 (2026-09-15).
Data as JSON: /api/errors/b8578640ce258a4a.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/mcp-tools/agentbbs-federation.ts:252
} catch {
return [];
}
}
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})`);
View on GitHub (pinned to 2602b642d9)