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

  1. Use an http:// or https:// URL for the peer endpoint
  2. If the peer serves another protocol, expose/proxy it behind an HTTP(S) endpoint registered in the federation
  3. Remove any file:// paths from peer configuration and supply a real network address
  4. 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

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


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)