{"record":{"id":"31777c5c2b8ca096","repo":"ruvnet/ruflo","slug":"label-must-be-a-canonical-unsigned-decimal-inte","errorCode":null,"errorMessage":"${label} must be a canonical unsigned decimal integer","messagePattern":"(.+?) must be a canonical unsigned decimal integer","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/codex/src/harness/unsigned-integer.ts","lineNumber":7,"sourceCode":"const CANONICAL_UNSIGNED = /^(?:0|[1-9][0-9]*)$/;\nconst MAX_UNSIGNED_64 = (1n << 64n) - 1n;\n\n/** Parse a decimal unsigned integer without accepting aliases such as +1, 01, hex, or whitespace. */\nexport function parseCanonicalUnsigned(value: string, label: string): bigint {\n  if (!CANONICAL_UNSIGNED.test(value)) {\n    throw new Error(`${label} must be a canonical unsigned decimal integer`);\n  }\n  const parsed = BigInt(value);\n  if (parsed > MAX_UNSIGNED_64) {\n    throw new Error(`${label} exceeds unsigned 64-bit range`);\n  }\n  return parsed;\n}\n","sourceCodeStart":1,"sourceCodeEnd":15,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/codex/src/harness/unsigned-integer.ts#L1-L15","documentation":"parseCanonicalUnsigned() accepts exactly one spelling of an unsigned integer: /^(?:0|[1-9][0-9]*)$/. It rejects leading zeros, '+', '0x' hex, underscores, surrounding whitespace, empty strings, and negatives. It is used for protocol fields such as inbox message sequence/cursor and fenced-lease version, where non-canonical spellings would break equality and ordering comparisons.","triggerScenarios":"Passing '01', '+1', ' 1', '0x10', '1_000', '-5', '' or 1e21-derived strings as message.sequence, inbox cursor, or lease version; JSON codecs that reformat numbers (padding, exponent form) feed these fields.","commonSituations":"A peer implementation serializes integers with a different formatter; a database or JSON store returns '01'; hand-crafted test fixtures use padded strings; values were concatenated instead of parsed then re-stringified.","solutions":["Check the label in the message ('message sequence', 'inbox cursor', 'lease version') to find the offending field","Emit plain decimal via BigInt.prototype.toString() or String(Number) and never pad or sign values","Round-trip test your serializer against /^(?:0|[1-9][0-9]*)$/ before sending"],"exampleFix":"// before\ncursor: String(seq).padStart(4, '0'); // '0042' -> throws\n// after\ncursor: BigInt(seq).toString(); // '42'","handlingStrategy":"type-guard","validationCode":"const CANONICAL = /^(?:0|[1-9][0-9]*)$/;\nfunction isCanonicalUnsigned(v: string): boolean { return CANONICAL.test(v); }","typeGuard":"const CANONICAL_UNSIGNED = /^(?:0|[1-9][0-9]*)$/;\nfunction isCanonicalUnsigned(v: unknown): v is string {\n  return typeof v === 'string' && CANONICAL_UNSIGNED.test(v);\n}","tryCatchPattern":"try { parseCanonicalUnsigned(cursor, 'inbox cursor'); } catch (e) { if (/canonical unsigned/.test(String(e))) return rejectPeer('non-canonical integer field'); throw e; }","preventionTips":["Always serialize these fields with BigInt(x).toString() or String(Number(x))","Property-test your serializer: output must match /^(?:0|[1-9][0-9]*)$/","Never pad, sign, or localize protocol numbers"],"tags":["validation","number-format","protocol","typescript"],"backgroundTag":"number-format-validation-failed","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}