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
- Upgrade both peers so the negotiated scheme agrees (see selectEnvelopeSignatureVersion and the peer's advertised protocols)
- Treat inbound messages with unknown signatureVersion as untrusted: drop and log, do not retry
- If you build envelopes manually, set metadata.signatureVersion only to 'jcs-v1' or omit it entirely
- 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
- Negotiate the scheme via selectEnvelopeSignatureVersion against the peer's advertised protocols
- Upgrade federation peers together to avoid version skew
- Set metadata.signatureVersion only to 'jcs-v1' or omit it entirely
- Treat unknown signature versions as untrusted input, never retry them
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
- Federation canonicalization rejects non-canonical numbers
- MCP initialization failed: ${initResponse.error.message}
- Buffer too small to be a valid RVFA file
- Invalid RVFA magic: expected "RVFA", got "${magic}"
- Header length extends beyond buffer
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/5b69eb124709668e.
Report an issue: GitHub.