ruvnet/ruflo · error · TypeError

Unsupported federation signature version: ${String(version)}

Error message

Unsupported federation signature version: ${String(version)}

What it means

envelopeSignatureVersion() reads message.metadata.signatureVersion: absent means 'legacy-v1', the exact string 'jcs-v1' is accepted, and anything else — numbers, booleans, or strings like 'jcs-v2' — throws a TypeError. Inbound envelopes with an unknown signature version cannot be verified, so they are rejected before any signature check rather than mis-verified under an assumed scheme.

Source

Thrown at v3/@claude-flow/plugin-agent-federation/src/application/inbound-dispatcher.ts:206

    if (prototype !== Object.prototype && prototype !== null) {
      throw new TypeError('Federation canonicalization accepts only plain objects');
    }

    const record = value as Record<string, unknown>;
    const entries = Object.keys(record)
      .sort()
      .map((key) => `${JSON.stringify(key)}:${canonicalizeJcsValue(record[key], ancestors)}`);
    return `{${entries.join(',')}}`;
  } finally {
    ancestors.delete(object);
  }
}

function envelopeSignatureVersion(message: AgentMessage): EnvelopeSignatureVersion {
  const version = (message.metadata as Record<string, unknown> | undefined)?.signatureVersion;
  if (version === undefined) return 'legacy-v1';
  if (version === 'jcs-v1') return version;
  throw new TypeError(`Unsupported federation signature version: ${String(version)}`);
}

export function selectEnvelopeSignatureVersion(
  mode: EnvelopeSignatureMode,
  peerProtocols: readonly string[],
  messageType?: string,
): EnvelopeSignatureVersion {
  const selected = mode === 'legacy'
    ? 'legacy-v1'
    : peerProtocols.includes(JCS_SIGNATURE_PROTOCOL)
      ? 'jcs-v1'
      : mode === 'prefer-jcs'
        ? 'legacy-v1'
        : null;
  if (selected === null) {
    throw new Error('PEER_SIGNATURE_PROTOCOL_UNSUPPORTED');
  }
  if (

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Upgrade both peers so the negotiated scheme agrees (see selectEnvelopeSignatureVersion and the peer's advertised protocols)
  2. Treat inbound messages with unknown signatureVersion as untrusted: drop and log, do not retry
  3. If you build envelopes manually, set metadata.signatureVersion only to 'jcs-v1' or omit it entirely
  4. Reject non-string signatureVersion at your ingress before it reaches the dispatcher

Example fix

// before
envelope.metadata.signatureVersion = 'jcs-v2';
// after
envelope.metadata.signatureVersion = 'jcs-v1'; // or omit the key for legacy-v1
Defensive patterns

Strategy: type-guard

Validate before calling

// at ingress: only accept known signature versions before dispatch
const sv = (msg.metadata as Record<string, unknown>)?.signatureVersion;
if (sv !== undefined && sv !== 'jcs-v1') {
  // untrusted envelope: drop and log, do not hand to the dispatcher
  log.warn('dropping envelope with unknown signatureVersion', sv);
  continue;
}

Type guard

type EnvelopeSignatureVersion = 'legacy-v1' | 'jcs-v1';
function isKnownSignatureVersion(v: unknown): v is EnvelopeSignatureVersion {
  return v === undefined || v === 'jcs-v1';
}

Try / catch

try {
  dispatcher.dispatch(msg);
} catch (e) {
  if (String(e).includes('Unsupported federation signature version')) {
    // version skew or tampering: quarantine the message, alert, do not retry
    quarantine(msg);
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: A peer running a newer release advertising 'jcs-v2'; a hand-crafted or tampered envelope with signatureVersion set to a non-string; another metadata field accidentally leaking into signatureVersion during envelope construction.

Common situations: Version skew across federation peers after a partial upgrade; adversarial probing with malformed envelopes; envelope builders copying whole metadata objects from unknown sources.

Related errors


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