{"record":{"id":"4a32fc1cfc7e665a","repo":"ruvnet/ruflo","slug":"inbox-cursor-must-be-a-non-negative-decimal-intege","errorCode":null,"errorMessage":"inbox cursor must be a non-negative decimal integer","messagePattern":"inbox cursor must be a non-negative decimal integer","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/codex/src/harness/in-memory-inbox-reference.ts","lineNumber":158,"sourceCode":"    const record = matches[0]!;\n    if (record.acknowledgedAt === undefined) record.acknowledgedAt = new Date(this.now()).toISOString();\n  }\n\n  pending(audience: string): InMemoryInboxRecord[] {\n    return this.records\n      .filter((record) => record.message.audience === audience && record.acknowledgedAt === undefined)\n      .map(clone);\n  }\n\n  quarantineRecords(): InMemoryQuarantinedMessage[] {\n    return this.quarantined.map(clone);\n  }\n\n  private parseCursor(cursor: string): bigint {\n    try {\n      return parseCanonicalUnsigned(cursor, 'inbox cursor');\n    } catch {\n      throw new Error('inbox cursor must be a non-negative decimal integer');\n    }\n  }\n\n  private quarantine(\n    message: HarnessMessage,\n    reason: InMemoryQuarantinedMessage['reason'],\n    quarantinedAt: string,\n  ): void {\n    this.quarantined.push({\n      issuer: message.issuer,\n      messageId: message.messageId,\n      reason,\n      quarantinedAt,\n    });\n  }\n}\n","sourceCodeStart":140,"sourceCodeEnd":175,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/codex/src/harness/in-memory-inbox-reference.ts#L140-L175","documentation":"Thrown by InMemoryHarnessInbox.receive(audience, cursor) when the resume cursor fails parseCanonicalUnsigned. The inbox stamps each message with strictly increasing decimal cursors ('1', '2', ...) from an internal BigInt counter, and resumes only from strings matching /^(?:0|[1-9][0-9]*)$/ within unsigned 64-bit range: no sign, no leading zeros ('01'), no whitespace, hex, or floats. The catch block discards the specific parse error, so both format violations and u64 overflow surface as this one generic message.","triggerScenarios":"Calling inbox.receive('worker-1', cursor) with '-1', '1e3', '0x1f', '12.5', ' 42', '01', '', 'null', 'undefined', or a numeric string above 18446744073709551615. Also passing a page index, an array offset, or an opaque/base64 cursor copied from a different pagination system.","commonSituations":"Persisting the cursor as a JS number and re-stringifying it (floats/rounding corrupt it); building cursors from offsets instead of reading message.cursor; optional config where cursor is undefined and interpolated as the string 'undefined'; migrating from another API whose cursors are base64 blobs.","solutions":["Pass only the cursor field of a previously received HarnessMessage, or omit the argument entirely (it defaults to '0', resuming from the oldest unacknowledged message)","Pre-validate with /^(?:0|[1-9][0-9]*)$/ (no leading zeros) and BigInt(cursor) <= 2n**64n-1n before calling receive","Store and transmit cursors as strings end-to-end; never round-trip through Number","To restart a consumer from the beginning, pass '0' explicitly rather than '' or null"],"exampleFix":"// before: lastOffset is a page counter, not a cursor\nfor await (const m of inbox.receive('worker', String(lastOffset))) { handle(m); }\n\n// after: use the cursor stamped on the last processed message, or '0' to start fresh\nconst cursor = lastMessage ? lastMessage.cursor : '0';\nfor await (const m of inbox.receive('worker', cursor)) { handle(m); lastMessage = m; }","handlingStrategy":"validation","validationCode":"const CANONICAL_CURSOR = /^(?:0|[1-9][0-9]*)$/;\nconst MAX_U64 = (1n << 64n) - 1n;\nfunction assertValidCursor(cursor: string): void {\n  if (!CANONICAL_CURSOR.test(cursor)) throw new TypeError(`invalid inbox cursor: ${JSON.stringify(cursor)}`);\n  if (BigInt(cursor) > MAX_U64) throw new RangeError('inbox cursor exceeds unsigned 64-bit range');\n}","typeGuard":"function isInboxCursor(value: unknown): value is string {\n  return typeof value === 'string'\n    && /^(?:0|[1-9][0-9]*)$/.test(value)\n    && BigInt(value) <= (1n << 64n) - 1n;\n}","tryCatchPattern":"try {\n  for await (const message of inbox.receive(audience, cursor)) { /* ... */ }\n} catch (error) {\n  if (error instanceof Error && error.message === 'inbox cursor must be a non-negative decimal integer') {\n    // cursor is unrecoverable: log it and restart from '0' (oldest unacknowledged)\n    logger.warn('bad cursor, resetting', { cursor });\n    cursor = '0';\n  } else throw error;\n}","preventionTips":["Always source the resume cursor from the cursor field of a received HarnessMessage","Treat cursors as opaque canonical strings; never construct them from offsets, page numbers, or Numbers","Pass '0' (or omit the parameter) to start from the oldest unacknowledged message"],"tags":["validation","cursor","pagination","in-memory-inbox"],"backgroundTag":"invalid-cursor-format","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}