{"record":{"id":"3240380cfc280121","repo":"ruvnet/ruflo","slug":"canonical-json-does-not-support-undefined","errorCode":null,"errorMessage":"canonical JSON does not support undefined","messagePattern":"canonical JSON does not support undefined","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/codex/src/harness/repository-state.ts","lineNumber":127,"sourceCode":"export function canonicalJson(value: unknown): string {\n  const ancestors = new Set<object>();\n  const encode = (item: unknown): string => {\n    if (item === null || typeof item === 'boolean') return JSON.stringify(item);\n    if (typeof item === 'string') {\n      assertUnicodeScalarString(item);\n      return JSON.stringify(item);\n    }\n    if (typeof item === 'number') {\n      if (\n        !Number.isFinite(item)\n        || Object.is(item, -0)\n        || (Number.isInteger(item) && !Number.isSafeInteger(item))\n      ) {\n        throw new Error('canonical JSON requires finite, safe, non-negative-zero numbers');\n      }\n      return JSON.stringify(item);\n    }\n    if (item === undefined) throw new Error('canonical JSON does not support undefined');\n    if (typeof item !== 'object') {\n      throw new Error(`canonical JSON does not support ${typeof item}`);\n    }\n    if (ancestors.has(item)) throw new Error('canonical JSON does not support cycles');\n    ancestors.add(item);\n    try {\n      if (Array.isArray(item)) return `[${item.map(encode).join(',')}]`;\n      const prototype = Object.getPrototypeOf(item);\n      if (prototype !== Object.prototype && prototype !== null) {\n        throw new Error('canonical JSON supports only arrays and plain objects');\n      }\n      const entries = Object.entries(item as Record<string, unknown>)\n        .sort(([left], [right]) => codeUnitCompare(left, right));\n      return `{${entries.map(([key, child]) => {\n        assertUnicodeScalarString(key);\n        return `${JSON.stringify(key)}:${encode(child)}`;\n      }).join(',')}}`;\n    } finally {","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/codex/src/harness/repository-state.ts#L109-L145","documentation":"canonicalJson refuses the value undefined at the top level or inside arrays, where it is observable (plain JSON.stringify would silently encode [undefined] as '[null]', hiding data loss). Note the asymmetry: inside plain objects, keys whose value is undefined are dropped silently by Object.entries and do not throw — only a directly encoded undefined does.","triggerScenarios":"canonicalJson(undefined) when an optional variable was never assigned; arrays built with explicit undefined holes (arr.push(cond ? value : undefined)); map() callbacks that return undefined on some branches.","commonSituations":"Optional evidence fields flowing into arrays; destructuring with missing defaults; conditional spreads that leave undefined elements in position.","solutions":["Use null to represent absent values explicitly in evidence payloads","Filter undefined out of arrays before canonicalization: arr.filter((x) => x !== undefined)","Narrow optional variables to a defined value before building the payload"],"exampleFix":"// before\nconst tags = items.map((i) => i.tag); // some undefined\nconst digest = canonicalJson({ tags });\n\n// after\nconst tags = items.map((i) => i.tag ?? null);\nconst digest = canonicalJson({ tags });","handlingStrategy":"validation","validationCode":"function stripUndefined(value: unknown): unknown {\n  if (Array.isArray(value)) return value.filter((item) => item !== undefined).map(stripUndefined);\n  if (typeof value === 'object' && value !== null) {\n    return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, stripUndefined(v)]));\n  }\n  return value;\n}","typeGuard":"function isDefined<T>(value: T | undefined): value is T {\n  return value !== undefined;\n}","tryCatchPattern":"try {\n  return canonicalJson(payload);\n} catch (error) {\n  if (error instanceof Error && error.message === 'canonical JSON does not support undefined') {\n    return canonicalJson(stripUndefined(payload));\n  }\n  throw error;\n}","preventionTips":["Use null (not undefined) to mean 'absent' inside evidence payloads","Filter undefined out of arrays built from conditional pushes or partial maps","Narrow optional variables before constructing the payload"],"tags":["canonical-json","undefined","serialization"],"backgroundTag":"undefined-serialization","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}