{"record":{"id":"cf13c08504ec275a","repo":"can1357/oh-my-pi","slug":"expected-number-got-typeof-value","errorCode":null,"errorMessage":"Expected number, got ${typeof value}","messagePattern":"Expected number, got (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/catalog/src/discovery/protobuf.ts","lineNumber":646,"sourceCode":"\t\tisDefault(value) {\n\t\t\treturn value === undefined;\n\t\t},\n\t};\n}\n\nfunction requireBoolean(value: unknown): boolean {\n\tif (typeof value === \"boolean\") return value;\n\tthrow new Error(`Expected boolean, got ${typeof value}`);\n}\n\nfunction requireBytes(value: unknown): Uint8Array {\n\tif (value instanceof Uint8Array) return value;\n\tthrow new Error(\"Expected Uint8Array\");\n}\n\nfunction requireNumber(value: unknown): number {\n\tif (typeof value === \"number\" && Number.isFinite(value)) return value;\n\tthrow new Error(`Expected number, got ${typeof value}`);\n}\n\nfunction requireInt32(value: unknown): number {\n\tif (typeof value === \"number\" && Number.isInteger(value)) return value | 0;\n\tthrow new Error(`Expected int32, got ${typeof value}`);\n}\nfunction requireString(value: unknown): string {\n\tif (typeof value === \"string\") return value;\n\tthrow new Error(`Expected string, got ${typeof value}`);\n}\n\nfunction requireBigInt(value: unknown): bigint {\n\tif (typeof value === \"bigint\") return value;\n\tif (typeof value === \"number\" && Number.isInteger(value)) return BigInt(value);\n\tif (typeof value === \"string\") return BigInt(value);\n\tthrow new Error(`Expected bigint, got ${typeof value}`);\n}\n","sourceCodeStart":628,"sourceCodeEnd":664,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/catalog/src/discovery/protobuf.ts#L628-L664","documentation":"Thrown by requireNumber, the validator for the `double` and `float` scalar kinds. It accepts only finite JavaScript numbers (`typeof value === \"number\" && Number.isFinite(value)`); anything else — strings, bigint, NaN, Infinity, null, undefined — throws with the value's `typeof`. The finite check is deliberate: protobuf double/float fields have no NaN/Infinity in this codec's value domain, and 64/32-bit float encoding of non-finites would silently corrupt the stream. Fired from encode/toJson/isDefault paths; the decode path (reader.double/float) always returns finite numbers.","triggerScenarios":"Specific: encoding a double/float field whose value came from a JSON parse that produced a string (\"3.14\") or null; passing a bigint (e.g. from a DB driver) into a float field; NaN or Infinity from an upstream division by zero or a placeholder in partial data; undefined for a required (non-optional) numeric field; calling toJson on a hand-built message without codec.create().","commonSituations":"Real-world: config/CSV/API inputs delivered as numeric strings; SQL drivers returning bigint for BIGINT columns mapped to float fields; sentinel values (Number.MAX_VALUE * 2, 1/0) leaking from computations; JSON Schema-validated data where \"number\" allowed strings in a lenient validator.","solutions":["Coerce at the boundary: `Number(value)` then guard with `Number.isFinite(n)` before constructing the message; reject or default non-finite results explicitly.","Parse strings with `Number.parseFloat`/`Number` rather than passing them through.","Convert bigints with `Number(bigint)` (mind precision loss) or change the field kind to \"int64\"/\"uint64\" if integer semantics matter.","Use codec.create() so TypeScript's inferred partial type flags wrong types statically; avoid `as any`."],"exampleFix":"// before\nconst msg = Metrics.create({ latencyMs: row.latency }); // row.latency: bigint | string\n// after\nconst n = Number(row.latency);\nif (!Number.isFinite(n)) throw new TypeError(`latency not finite: ${row.latency}`);\nconst msg = Metrics.create({ latencyMs: n });","handlingStrategy":"validation","validationCode":"function toFiniteNumber(v: unknown): number {\n  const n = typeof v === \"bigint\" ? Number(v) : typeof v === \"string\" ? Number(v) : v;\n  if (typeof n !== \"number\" || !Number.isFinite(n)) {\n    throw new TypeError(`float/double field needs a finite number, got ${String(v)}`);\n  }\n  return n;\n}","typeGuard":"function isFiniteNumber(v: unknown): v is number {\n  return typeof v === \"number\" && Number.isFinite(v);\n}","tryCatchPattern":"try {\n  return MyMsg.encode(value);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith(\"Expected number, got \")) {\n    throw new TypeError(`numeric field '${fieldName}' got ${err.message}; coerce strings/bigints and reject NaN/Infinity first`);\n  }\n  throw err;\n}","preventionTips":["Coerce and validate numeric inputs (strings, bigints) at the data boundary with Number() + Number.isFinite().","Guard computations that can yield NaN/Infinity (division, overflow) before assigning to float fields.","Use codec.create() with inferred types to catch mismatches statically.","Use int64/uint64 kinds for integer values instead of routing bigints through double fields."],"tags":["protobuf","type-validation","numeric","encode"],"backgroundTag":"unexpected-field-type","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}