{"record":{"id":"b8578640ce258a4a","repo":"ruvnet/ruflo","slug":"peer-url-is-not-a-valid-url","errorCode":null,"errorMessage":"peer url is not a valid URL","messagePattern":"peer url is not a valid URL","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/mcp-tools/agentbbs-federation.ts","lineNumber":252,"sourceCode":"  } catch {\n    return [];\n  }\n}\n\nfunction writePeers(basePath: string, peers: FederationPeer[]): void {\n  ensureDir(basePath);\n  writeFileSync(peersPath(basePath), JSON.stringify(peers, null, 2) + '\\n');\n}\n\n/**\n * Reject anything that is not a plain http(s) URL to a host.\n *\n * Blocks credentials-in-URL (they would be logged), and non-http schemes such\n * as `file:` which would turn a peer entry into a local file read.\n */\nexport function validatePeerUrl(raw: string): string {\n  let u: URL;\n  try { u = new URL(raw); } catch { throw new Error('peer url is not a valid URL'); }\n  if (u.protocol !== 'http:' && u.protocol !== 'https:') {\n    throw new Error('peer url must be http or https');\n  }\n  if (u.username || u.password) throw new Error('peer url must not embed credentials');\n  return u.origin;\n}\n\nexport function addPeer(\n  basePath: string,\n  input: { nodeId: string; url: string; publicKey: string; label?: string },\n): FederationPeer {\n  if (!NODE_ID_RE.test(input.nodeId ?? '')) throw new Error('nodeId must be 16 lowercase hex chars');\n  if (!HEX64_RE.test(input.publicKey ?? '')) throw new Error('publicKey must be 64 lowercase hex chars');\n  const url = validatePeerUrl(String(input.url));\n\n  const peers = readPeers(basePath);\n  if (peers.length >= MAX_PEERS) throw new Error(`peer registry is full (${MAX_PEERS})`);\n","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/ruvnet/ruflo/blob/2602b642d92234c710ffbe96bfb33007d481ceab/v3/@claude-flow/cli/src/mcp-tools/agentbbs-federation.ts#L234-L270","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\naddPeer(base, { nodeId: '0a1b2c3d4e5f6071', url: 'peer.example.com', publicKey: PK });\n// after\naddPeer(base, { nodeId: '0a1b2c3d4e5f6071', url: 'https://peer.example.com', publicKey: PK });","handlingStrategy":"validation","validationCode":"function isParsableUrl(raw: string): boolean {\n  try { new URL(raw); return true; } catch { return false; }\n}\nif (!isParsableUrl(peerUrl)) throw new Error(`peer url must be an absolute URL with scheme: ${peerUrl}`);","typeGuard":"function isHttpUrl(raw: string): raw is string {\n  try { const u = new URL(raw); return u.protocol === 'http:' || u.protocol === 'https:'; } catch { return false; }\n}","tryCatchPattern":"try {\n  const origin = validatePeerUrl(rawUrl);\n} catch (e) {\n  if (/peer url/.test(e.message)) {\n    console.error(`Invalid peer URL '${rawUrl}': ${e.message}`);\n    // prompt user / abort registration\n  } else throw e;\n}","preventionTips":["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"],"tags":["url","validation","network"],"backgroundTag":"invalid-url","analyzedSha":"2602b642d92234c710ffbe96bfb33007d481ceab","analyzedAt":"2026-09-15T22:58:14.805Z","contentChangedAt":"2026-09-15T22:58:14.805Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}