{"record":{"id":"46d1a97d7647eea2","repo":"ruvnet/ruflo","slug":"hextobytes-odd-length-hex-string-46d1a9","errorCode":null,"errorMessage":"hexToBytes: odd-length hex string","messagePattern":"hexToBytes: odd-length hex string","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"plugins/ruflo-neural-trader/src/signed-attribution.ts","lineNumber":386,"sourceCode":"    name: item.name,\n    score: item.score,\n    rank: i + 1,\n  }));\n}\n\n/* ---------------------------------------------------------------------- */\n/* Helpers                                                                */\n/* ---------------------------------------------------------------------- */\n\nfunction canonicalBytes(body: SignedAttributionArtifactBody): Uint8Array {\n  const message = JSON.stringify(body);\n  return new TextEncoder().encode(message);\n}\n\nfunction hexToBytes(hex: string): Uint8Array {\n  const clean = hex.replace(/^0x/, '');\n  if (clean.length % 2 !== 0) {\n    throw new Error('hexToBytes: odd-length hex string');\n  }\n  const out = new Uint8Array(clean.length / 2);\n  for (let i = 0; i < out.length; i++) {\n    out[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n  }\n  return out;\n}\n\nfunction bytesToHex(bytes: Uint8Array): string {\n  let s = '';\n  for (let i = 0; i < bytes.length; i++) {\n    s += bytes[i].toString(16).padStart(2, '0');\n  }\n  return s;\n}\n\n/**\n * Mulberry32 — small, fast, deterministic PRNG. Same algorithm everywhere","sourceCodeStart":368,"sourceCodeEnd":404,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/plugins/ruflo-neural-trader/src/signed-attribution.ts#L368-L404","documentation":"session resume loads <sessionId>.json from .claude-flow/sessions/ under process.cwd() inside a single try block that covers file read AND JSON.parse; any failure in that block is collapsed into 'Session not found: <id>'. So the message can mean the file is genuinely missing, but also that it is unreadable or corrupt — and since sessions live on disk keyed by the server's working directory, resuming from a different cwd guarantees the miss. Checksum mismatches do NOT throw; they only append to an errors array.","triggerScenarios":"session_resume with an ID that was never saved or was saved in another process run from a different directory; the .claude-flow/sessions/<id>.json file was deleted or never flushed (crash before save); the JSON file is truncated/corrupt so JSON.parse throws and gets swallowed into the same message; sessionId casing mismatch on case-sensitive filesystems.","commonSituations":"Starting the MCP server from a different directory between runs (sessions are cwd-relative, not global); cleanup scripts wiping .claude-flow/; assuming sessions persist across container restarts when the dir was never mounted.","solutions":["Verify the file exists before resuming: ls .claude-flow/sessions/<sessionId>.json from the server's working directory","Run the MCP server from the same directory the session was created in — the session store is rooted at process.cwd()","List available sessions first (session files in .claude-flow/sessions/) and confirm the exact ID including case","If the file exists but is corrupt (0 bytes / cut off), delete it and start a fresh session — the error message hides JSON.parse failures, so test with: node -e \"JSON.parse(require('fs').readFileSync(process.argv[1],'utf8'))\" .claude-flow/sessions/<id>.json","Persist .claude-flow/sessions across container restarts via a mounted volume"],"exampleFix":"// before\nawait client.callTool('session_resume', { sessionId }); // throws [1127] when run from another cwd\n\n// after: pre-check existence relative to the server's cwd\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nconst file = join(process.cwd(), '.claude-flow/sessions', `${sessionId}.json`);\nif (!existsSync(file)) throw new Error(`No session file at ${file} — start the MCP server in the session's original directory`);\nawait client.callTool('session_resume', { sessionId });","handlingStrategy":"validation","validationCode":"import { existsSync, readFileSync } from 'fs';\nimport { join } from 'path';\n\nfunction sessionFileReadable(sessionId: string, cwd = process.cwd()): boolean {\n  const file = join(cwd, '.claude-flow/sessions', `${sessionId}.json`);\n  if (!existsSync(file)) return false;\n  try { JSON.parse(readFileSync(file, 'utf-8')); return true; } // catches the corrupt-JSON case\n  catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await client.callTool('session_resume', { sessionId });\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Session not found')) {\n    // message also covers unreadable/corrupt files — check the file directly to distinguish\n    if (!sessionFileReadable(sessionId)) throw new Error(`session ${sessionId} missing or corrupt under cwd`);\n  }\n  throw e;\n}","preventionTips":["Always run the MCP server from the same directory that created the session","Mount .claude-flow/sessions as a volume in containers so sessions survive restarts","Save immediately after important state changes instead of relying on a later resume"],"tags":["mcp","session","not-found","state"],"backgroundTag":"session-not-found","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}