{"record":{"id":"cd4bab44b15d5908","repo":"ruvnet/ruflo","slug":"federation-canonicalization-rejects-unsafe-integer","errorCode":null,"errorMessage":"Federation canonicalization rejects unsafe integers","messagePattern":"Federation canonicalization rejects unsafe integers","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/plugin-agent-federation/src/application/inbound-dispatcher.ts","lineNumber":155,"sourceCode":" * Federation messages are wrapped as `AgentMessage{id, type, payload,\n * metadata}` on the wire. The `payload` is the actual FederationEnvelope\n * (per `plugin.ts sendToNode`); we canonicalize the payload + the\n * metadata so the receiver verifies the same bytes the sender signed.\n */\nfunction canonicalizeJcsValue(value: unknown, ancestors: Set<object>): string {\n  if (value === null) return 'null';\n\n  switch (typeof value) {\n    case 'boolean':\n      return value ? 'true' : 'false';\n    case 'string':\n      return JSON.stringify(value);\n    case 'number':\n      if (!Number.isFinite(value) || Object.is(value, -0)) {\n        throw new TypeError('Federation canonicalization rejects non-canonical numbers');\n      }\n      if (Number.isInteger(value) && !Number.isSafeInteger(value)) {\n        throw new TypeError('Federation canonicalization rejects unsafe integers');\n      }\n      return JSON.stringify(value);\n    case 'bigint':\n    case 'function':\n    case 'symbol':\n    case 'undefined':\n      throw new TypeError(`Federation canonicalization rejects ${typeof value}`);\n    case 'object':\n      break;\n    default:\n      throw new TypeError(`Federation canonicalization rejects ${typeof value}`);\n  }\n\n  const object = value as object;\n  if (ancestors.has(object)) {\n    throw new TypeError('Federation canonicalization rejects cyclic values');\n  }\n  ancestors.add(object);","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/plugin-agent-federation/src/application/inbound-dispatcher.ts#L137-L173","documentation":"JCS canonicalization rejects integers beyond the safe range: values where Number.isInteger is true but Number.isSafeInteger is false (magnitude above 2^53 - 1). Such values silently lose precision in IEEE-754 doubles, so sender and receiver could canonicalize different bytes and signature verification would fail spuriously or, worse, verify the wrong value.","triggerScenarios":"64-bit IDs (snowflake IDs, database bigint keys) or nanosecond timestamps placed as JSON numbers in signed metadata; values received from serializers in other languages that happily emit 64-bit JSON integers.","commonSituations":"Porting pipelines from languages whose JSON writers emit int64 numbers; mixing JS with services that use 64-bit identifiers; log-precision timestamps in envelopes.","solutions":["Serialize 64-bit identifiers and timestamps as strings inside signed envelopes","Use safe-integer ID generation, or split hi/lo halves, for values that must remain numeric","Validate at the boundary: reject integers where Number.isSafeInteger is false before signing"],"exampleFix":"// before\nmetadata.id = snowflakeId; // 64-bit integer, not safe\n// after\nmetadata.id = String(snowflakeId);","handlingStrategy":"type-guard","validationCode":"// boundary check: reject unsafe integers before signing\nfunction assertSafeNumbers(value: unknown): void {\n  if (typeof value === 'number' && Number.isInteger(value) && !Number.isSafeInteger(value)) {\n    throw new RangeError('unsafe integer in signed payload: ' + value);\n  }\n  if (typeof value === 'object' && value !== null) {\n    for (const v of Object.values(value)) assertSafeNumbers(v);\n  }\n}","typeGuard":"function isSafeCanonicalInteger(v: unknown): v is number {\n  return (\n    typeof v === 'number' &&\n    Number.isInteger(v) &&\n    Number.isSafeInteger(v)\n  );\n}","tryCatchPattern":null,"preventionTips":["Serialize 64-bit IDs and high-resolution timestamps as strings","Use safe-integer ID generators for values that end up in envelopes","Validate external numbers at the trust boundary before signing","Watch for int64 JSON from non-JS services"],"tags":["canonicalization","jcs","integers","precision"],"backgroundTag":"unsafe-integer","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}