ruvnet/ruflo · error · Error
subnet ${subnet} too small for mesh IPs
Error message
subnet ${subnet} too small for mesh IPs What it means
deriveMeshIP rejects the configured mesh subnet because after removing the network and broadcast addresses of each /24 it cannot hold the mesh IPs required — the address space is too small to assign deterministic collision-resistant host addresses to peers.
Source
Thrown at v3/@claude-flow/plugin-agent-federation/src/domain/value-objects/wg-config.ts:119
*
* Strategy: sha256(nodeId) → top bytes interpreted as host portion of the
* subnet, clamped to avoid the network address (.0) and broadcast (.255)
* of any /24 inside the subnet. This is collision-resistant in the
* birthday-paradox sense — see ADR for thresholds.
*
* `usedIPs` (when provided) gives previously-assigned IPs in the mesh.
* If the derived IP is already taken, the function probes `nodeId + '\x00'`,
* `nodeId + '\x01'`, … until a free slot is found. Bounded to 1024 probes;
* exceeding that means the subnet is functionally exhausted and the caller
* should jump to a larger range (see ADR `10.50.0.0/12` recommendation).
*/
export function deriveMeshIP(
nodeId: string,
subnet: string = DEFAULT_MESH_SUBNET,
usedIPs: ReadonlySet<string> = new Set(),
): string {
const { base, prefix } = parseCidr(subnet);
if (prefix > 30) throw new Error(`subnet ${subnet} too small for mesh IPs`);
const hostBits = 32 - prefix;
const hostMask = hostBits >= 32 ? 0xffffffff : ((1 << hostBits) - 1) >>> 0;
const networkBase = (base & ~hostMask) >>> 0;
for (let probe = 0; probe < 1024; probe++) {
const input = probe === 0 ? nodeId : `${nodeId}\x00${probe}`;
const hash = createHash('sha256').update(input).digest();
// Use the first 4 bytes as the host portion.
const hashHost = ((hash[0] << 24) | (hash[1] << 16) | (hash[2] << 8) | hash[3]) >>> 0;
let candidate = (networkBase | (hashHost & hostMask)) >>> 0;
const lastOctet = candidate & 0xff;
// Avoid .0 (network) and .255 (broadcast) of each /24 slice. Cheap
// clamp: bump to .1 if landing on .0, or .254 if landing on .255.
if (lastOctet === 0) candidate = (candidate | 1) >>> 0;
else if (lastOctet === 255) candidate = (candidate & ~1) >>> 0;
const ip = `${ipToString(candidate)}/32`;
if (!usedIPs.has(ip)) return ip;
}View on GitHub (pinned to fa13ee4ad6)
Solutions
- Choose a wider subnet (e.g. /24) that fits the expected number of mesh nodes.
- Reduce the mesh size or split into multiple subnets.
Defensive patterns
Strategy: validation
When it happens
Trigger: The configured mesh subnet does not have enough address space to assign mesh IPs.
Common situations: Subnet like /30 or smaller chosen for a mesh that needs host addresses.
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/9b6a4a413cfd5e9d.
Report an issue: GitHub.