{"record":{"id":"0e85215425be347a","repo":"github/copilot-sdk","slug":"negative-zero","errorCode":"negative_zero","errorMessage":"${context.label} contains negative zero at ${path}; normalize it to 0","messagePattern":"(.+?) contains negative zero at (.+?); normalize it to 0","errorType":"validation","errorClass":"ResponseError","httpStatus":null,"severity":"error","filePath":"nodejs/src/session.ts","lineNumber":2321,"sourceCode":"                path\n            );\n        }\n        if (current === null || typeof current === \"boolean\" || typeof current === \"string\") {\n            return;\n        }\n        if (typeof current === \"number\") {\n            if (!Number.isFinite(current)) {\n                throw strictJsonValidationError(\n                    context,\n                    \"non_finite_number\",\n                    `${context.label} contains a non-finite number at ${path}`,\n                    path\n                );\n            }\n            // JSON serializes -0 as \"0\", so a journaled -0 would come back as 0\n            // after a resume and break the lossless replay guarantee.\n            if (Object.is(current, -0)) {\n                throw strictJsonValidationError(\n                    context,\n                    \"negative_zero\",\n                    `${context.label} contains negative zero at ${path}; normalize it to 0`,\n                    path\n                );\n            }\n            return;\n        }\n        if (\n            typeof current === \"function\" ||\n            typeof current === \"symbol\" ||\n            typeof current === \"bigint\"\n        ) {\n            throw strictJsonValidationError(\n                context,\n                \"unsupported_type\",\n                `${context.label} contains a function, symbol, or BigInt at ${path}`,\n                path","sourceCodeStart":2303,"sourceCodeEnd":2339,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/nodejs/src/session.ts#L2303-L2339","documentation":"The strict JSON validator rejects -0 because JSON.stringify serializes it as \"0\", so a journaled -0 would silently come back as 0 after a session resume, breaking the library's lossless replay guarantee. The error includes the path to the offending value.","triggerScenarios":"Returning a factory result or step value equal to -0, typically produced by expressions like -0, 0 * -1, -1 % 0 === -0? (no, but -0 arises from Math.round(-0.4), Math.sign(-0), Object.freeze artifacts, or negating zero).","commonSituations":"Math.round(-0.4) yielding -0, Math.sign(-0), negating a zero computed elsewhere, deserializing numeric data that contains -0, and clone/copy helpers preserving the signed zero.","solutions":["Locate the value via the error's `path` and normalize it: `Object.is(v, -0) ? 0 : v`.","Add `+ value` or `value + 0` normalization at the factory boundary before returning journaled data.","Fix the upstream arithmetic so signed zero is never produced (e.g. use Math.round(Math.abs(x)) * sign)."],"exampleFix":"// before\nreturn { delta: Math.round(-0.4) }; // -0\n// after\nreturn { delta: Math.round(-0.4) + 0 }; // 0","handlingStrategy":"validation","validationCode":"function normalizeNegativeZero(v) {\n  if (typeof v === \"number\") return Object.is(v, -0) ? 0 : v;\n  if (Array.isArray(v)) return v.map(normalizeNegativeZero);\n  if (v && typeof v === \"object\") return Object.fromEntries(Object.entries(v).map(([k, x]) => [k, normalizeNegativeZero(x)]));\n  return v;\n}","typeGuard":"const isNegativeZero = (v: unknown): boolean => Object.is(v, -0);","tryCatchPattern":"try {\n  session.runFactory(step);\n} catch (e) {\n  if (e?.details?.category === \"negative_zero\") {\n    console.error(`Normalize -0 at ${e.details.path} to 0`);\n  } else throw e;\n}","preventionTips":["Add `+ value` or `value + 0` when normalizing numbers near zero (Math.round, Math.sign).","Include -0 checks in JSON boundary tests.","Avoid negating potentially zero values without normalization."],"tags":["json","validation","numbers","factory-result"],"backgroundTag":"json-serialization-failed","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}