ruvnet/ruflo · error

FederationBridge.decode: expected type 'claim-event', got '$

Error message

FederationBridge.decode: expected type 'claim-event', got '${envelope.type}'

What it means

FederationBridge.decode only accepts envelopes whose type equals the claim-event message type ('claim-event'). A transport that multiplexes several message types will hand the decoder foreign envelopes; decode throws on the type mismatch instead of mis-parsing the payload. Signature verification is deliberately out of scope — it happens in the transport before decode runs.

Source

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

        event,
        vclock,
        originNodeId: this.opts.nodeId,
        hlc,
      },
    };

    await this.opts.transport.publish(envelope);
    return envelope;
  }

  /**
   * 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. Dispatch on envelope.type before decoding: only call decode when the type matches the claim-event constant
  2. Publish claim events on a dedicated topic/channel so foreign types cannot reach this decoder
  3. After any type rename, align the CLAIM_EVENT_MESSAGE_TYPE constant across all nodes before deploying

Example fix

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

// after
if (envelope.type === 'claim-event') {
  const payload = bridge.decode(envelope);
} else {
  handleOtherMessage(envelope);
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (envelope.type !== 'claim-event') {
  routeElsewhere(envelope); // heartbeat, handshake, custom types
} else {
  const payload = bridge.decode(envelope);
}

Type guard

function isClaimEventEnvelope(e: FederationEnvelope): boolean {
  return e.type === 'claim-event';
}

Try / catch

try { payload = bridge.decode(envelope); }
catch (e) { if (e instanceof Error && e.message.includes("expected type 'claim-event'")) { dropOrRoute(envelope); } else throw e; }

Prevention

When it happens

Trigger: Routing a heartbeat, handshake, or custom envelope into FederationBridge.decode; a peer publishing claim events under a renamed type string after a schema change; hand-built test envelopes using type: 'claim' or 'ClaimEvent'.

Common situations: Shared message bus/channel carrying multiple message types with no type dispatch; version skew between bridge implementations after a type rename; test fixtures constructing envelopes by hand.

Related errors


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