can1357/oh-my-pi · error · Error
Expected number, got ${typeof value}
Error message
Expected number, got ${typeof value} What it means
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.
Source
Thrown at packages/catalog/src/discovery/protobuf.ts:646
isDefault(value) {
return value === undefined;
},
};
}
function requireBoolean(value: unknown): boolean {
if (typeof value === "boolean") return value;
throw new Error(`Expected boolean, got ${typeof value}`);
}
function requireBytes(value: unknown): Uint8Array {
if (value instanceof Uint8Array) return value;
throw new Error("Expected Uint8Array");
}
function requireNumber(value: unknown): number {
if (typeof value === "number" && Number.isFinite(value)) return value;
throw new Error(`Expected number, got ${typeof value}`);
}
function requireInt32(value: unknown): number {
if (typeof value === "number" && Number.isInteger(value)) return value | 0;
throw new Error(`Expected int32, got ${typeof value}`);
}
function requireString(value: unknown): string {
if (typeof value === "string") return value;
throw new Error(`Expected string, got ${typeof value}`);
}
function requireBigInt(value: unknown): bigint {
if (typeof value === "bigint") return value;
if (typeof value === "number" && Number.isInteger(value)) return BigInt(value);
if (typeof value === "string") return BigInt(value);
throw new Error(`Expected bigint, got ${typeof value}`);
}
View on GitHub (pinned to 9690622007)
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`.
Example fix
// before
const msg = Metrics.create({ latencyMs: row.latency }); // row.latency: bigint | string
// after
const n = Number(row.latency);
if (!Number.isFinite(n)) throw new TypeError(`latency not finite: ${row.latency}`);
const msg = Metrics.create({ latencyMs: n }); Defensive patterns
Strategy: validation
Validate before calling
function toFiniteNumber(v: unknown): number {
const n = typeof v === "bigint" ? Number(v) : typeof v === "string" ? Number(v) : v;
if (typeof n !== "number" || !Number.isFinite(n)) {
throw new TypeError(`float/double field needs a finite number, got ${String(v)}`);
}
return n;
} Type guard
function isFiniteNumber(v: unknown): v is number {
return typeof v === "number" && Number.isFinite(v);
} Try / catch
try {
return MyMsg.encode(value);
} catch (err) {
if (err instanceof Error && err.message.startsWith("Expected number, got ")) {
throw new TypeError(`numeric field '${fieldName}' got ${err.message}; coerce strings/bigints and reject NaN/Infinity first`);
}
throw err;
} Prevention
- 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.
When it happens
Trigger: 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().
Common situations: 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.
Related errors
- Expected boolean, got ${typeof value}
- Expected Uint8Array
- Expected int32, got ${typeof value}
- {field} must be a number
- Unsupported protobuf wire type ${wireType} at byte ${reader.
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/cf13c08504ec275a.
Report an issue: GitHub.