ruvnet/ruflo · error

FederationBridge.decode: payload missing required fields

Error message

FederationBridge.decode: payload missing required fields

What it means

decode requires all four payload fields — event, vclock, hlc, and originNodeId — to be present; missing any one throws. These carry the domain event, causal history, and origin identity, so a partial payload cannot be reconstructed into a federated claim event.

Source

Thrown at v3/@claude-flow/claims/src/infrastructure/federation-bridge.ts:156

  }

  /**
   * Decode an incoming envelope back into the claim event + vclock + hlc
   * tuple. Validates the envelope shape; does NOT verify the signature
   * (that's the transport's job, before this method is called).
   */
  decode(envelope: FederationEnvelope): ClaimEventEnvelopePayload {
    if (envelope.type !== CLAIM_EVENT_MESSAGE_TYPE) {
      throw new Error(
        `FederationBridge.decode: expected type '${CLAIM_EVENT_MESSAGE_TYPE}', got '${envelope.type}'`,
      );
    }
    const payload = envelope.payload as ClaimEventEnvelopePayload;
    if (!payload || typeof payload !== 'object') {
      throw new Error('FederationBridge.decode: payload missing or non-object');
    }
    if (!payload.event || !payload.vclock || !payload.hlc || !payload.originNodeId) {
      throw new Error('FederationBridge.decode: payload missing required fields');
    }
    return payload;
  }
}

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Publish only via encode(), which emits the full field set
  2. Pin all federated nodes to a bridge version that emits event/vclock/hlc/originNodeId before admitting new traffic
  3. Log the rejected envelope with its missing keys to identify the misbehaving producer quickly

Example fix

// before
const payload = bridge.decode(envelope);

// after
const p = envelope.payload as Record<string, unknown>;
for (const k of ['event', 'vclock', 'hlc', 'originNodeId']) {
  if (!p?.[k]) throw new Error(`envelope missing ${k}`);
}
const payload = bridge.decode(envelope);
Defensive patterns

Strategy: type-guard

Validate before calling

const p = envelope.payload as Record<string, unknown> | undefined;
const complete = !!p && !!p.event && !!p.vclock && !!p.hlc && !!p.originNodeId;
if (!complete) { reject(envelope); } else { const payload = bridge.decode(envelope); }

Type guard

function isClaimEventPayload(p: unknown): p is ClaimEventEnvelopePayload {
  if (typeof p !== 'object' || p === null) return false;
  const o = p as Record<string, unknown>;
  return !!o.event && !!o.vclock && !!o.hlc && !!o.originNodeId;
}

Try / catch

try { payload = bridge.decode(envelope); }
catch (e) { if (e instanceof Error && e.message.includes('missing required fields')) { rejectWithDetail(envelope); } else throw e; }

Prevention

When it happens

Trigger: A peer running an older bridge version that omits a field (commonly originNodeId); hand-serialized payloads; JSON round-trips that drop undefined keys; payloads built with object spread where some keys are undefined.

Common situations: Rolling upgrades with mixed node versions; abbreviated test fixtures; a producer that conditionally sets fields depending on message content.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/590e32f5b9628c1d. Report an issue: GitHub.