{"id":"28f41809f2cc6506","repo":"colinhacks/zod","slug":"cannot-mix-number-and-bigint-in-multiple-of-check","errorCode":null,"errorMessage":"Cannot mix number and bigint in multiple_of check.","messagePattern":"Cannot mix number and bigint in multiple_of check\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/zod/src/v4/core/checks.ts","lineNumber":178,"sourceCode":"  def: $ZodCheckMultipleOfDef<T>;\n  issc: errors.$ZodIssueNotMultipleOf;\n}\n\nexport interface $ZodCheckMultipleOf<T extends number | bigint = number | bigint> extends $ZodCheck<T> {\n  _zod: $ZodCheckMultipleOfInternals<T>;\n}\n\nexport const $ZodCheckMultipleOf: core.$constructor<$ZodCheckMultipleOf<number | bigint>> =\n  /*@__PURE__*/ core.$constructor(\"$ZodCheckMultipleOf\", (inst, def) => {\n    $ZodCheck.init(inst, def);\n\n    inst._zod.onattach.push((inst) => {\n      inst._zod.bag.multipleOf ??= def.value;\n    });\n\n    inst._zod.check = (payload) => {\n      if (typeof payload.value !== typeof def.value)\n        throw new Error(\"Cannot mix number and bigint in multiple_of check.\");\n      const isMultiple =\n        typeof payload.value === \"bigint\"\n          ? payload.value % (def.value as bigint) === BigInt(0)\n          : util.floatSafeRemainder(payload.value, def.value as number) === 0;\n\n      if (isMultiple) return;\n      payload.issues.push({\n        origin: typeof payload.value as \"number\",\n        code: \"not_multiple_of\",\n        divisor: def.value as number,\n        input: payload.value,\n        inst,\n        continue: !def.abort,\n      });\n    };\n  });\n\n/////////////////////////////////////","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/colinhacks/zod/blob/912f0f51b0ced654d0069741e7160834dca742ee/packages/zod/src/v4/core/checks.ts#L160-L196","documentation":"The `multiple_of` check (checks.ts:168) computes divisibility differently for numbers (float-safe remainder) vs bigints (native `%`). To pick the right branch it asserts `typeof payload.value === typeof def.value` at checks.ts:177 and throws if they differ. This is a parse-time throw, not construction-time: it fires when the runtime input type does not match the divisor's type.","triggerScenarios":"Defining `z.bigint().multipleOf(5)` (5 is a plain number) then `.parse(BigInt(10))`; OR `z.number().multipleOf(BigInt(5))` then `.parse(10)`. Also reachable by feeding a bigint into a number schema with a numeric divisor or vice versa via `.safeParse` on mixed data.","commonSituations":"Forgetting the `BigInt()` wrapper on the divisor when building a bigint schema; deserializing JSON (which has no bigint) into a bigint schema; a code path that sometimes receives a number and sometimes a bigint; refactoring a number schema to bigint without updating the divisor.","solutions":["Match the divisor type to the schema: `z.bigint().multipleOf(BigInt(5))` for bigint, `z.number().multipleOf(5)` for number.","Normalize the input to the expected type before parsing (e.g. `BigInt(x)` for bigint schemas).","If inputs are genuinely mixed, split into two schemas and branch on `typeof` before parsing."],"exampleFix":"// before\nconst schema = z.bigint().multipleOf(5); // 5 is number -> throws on parse\nschema.parse(BigInt(10));\n// after\nconst schema = z.bigint().multipleOf(BigInt(5));\nschema.parse(BigInt(10));","handlingStrategy":"validation","validationCode":"// Ensure divisor type matches schema type before constructing.\nfunction bigintMultipleOf(divisor: bigint) {\n  return z.bigint().multipleOf(divisor); // divisor MUST be bigint\n}\nfunction numberMultipleOf(divisor: number) {\n  return z.number().multipleOf(divisor); // divisor MUST be number\n}","typeGuard":"function isBigIntSchemaDivisor(v: unknown): v is bigint {\n  return typeof v === \"bigint\";\n}\n// before building: ensure typeof(schema input) === typeof(divisor)","tryCatchPattern":"try {\n  schema.parse(input);\n} catch (e) {\n  if (e instanceof Error && /Cannot mix number and bigint/.test(e.message)) {\n    // normalize input type and retry, or report a typed error\n  }\n  throw e;\n}","preventionTips":["Always wrap bigint divisors in `BigInt()`, never pass a raw number literal.","Keep number and bigint schemas on separate code paths; do not branch input by type into one schema.","At JSON boundaries (no bigint), coerce to BigInt before parsing a bigint schema."],"tags":["bigint","number","multiple-of","type-mismatch","parse-time"],"analyzedSha":"912f0f51b0ced654d0069741e7160834dca742ee","analyzedAt":"2026-08-03T17:41:55.908Z","schemaVersion":2}