jackwener/OpenCLI · error · ArgumentError
Argument "${argDef.name}" must be a valid number. Received:
Error message
Argument "${argDef.name}" must be a valid number. Received: "${val}" What it means
When an argument definition declares type 'int' or 'number', coerceAndValidateArgs converts the supplied value with Number(). If the result is not finite (NaN/Infinity), it throws ArgumentError stating the value must be a valid number. Note 'int' additionally requires an integer (separate error).
Source
Thrown at src/execution.ts:71
export function coerceAndValidateArgs(cmdArgs: Arg[], kwargs: CommandArgs): CommandArgs {
const result: CommandArgs = { ...kwargs };
for (const argDef of cmdArgs) {
const val = result[argDef.name];
if (argDef.required && (val === undefined || val === null || val === '')) {
throw new ArgumentError(
`Argument "${argDef.name}" is required.`,
argDef.help ?? `Provide a value for --${argDef.name}`,
);
}
if (val !== undefined && val !== null) {
if (argDef.type === 'int' || argDef.type === 'number') {
const num = Number(val);
if (!Number.isFinite(num)) {
throw new ArgumentError(`Argument "${argDef.name}" must be a valid number. Received: "${val}"`);
}
if (argDef.type === 'int' && !Number.isInteger(num)) {
throw new ArgumentError(`Argument "${argDef.name}" must be a valid integer. Received: "${val}"`);
}
result[argDef.name] = num;
} else if (argDef.type === 'boolean' || argDef.type === 'bool') {
if (typeof val === 'string') {
const lower = val.toLowerCase();
if (lower === 'true' || lower === '1') result[argDef.name] = true;
else if (lower === 'false' || lower === '0') result[argDef.name] = false;
else throw new ArgumentError(`Argument "${argDef.name}" must be a boolean (true/false). Received: "${val}"`);
} else {
result[argDef.name] = Boolean(val);
}
}
const coercedVal = result[argDef.name];
if (argDef.choices && argDef.choices.length > 0) {View on GitHub (pinned to 49907e53dc)
Solutions
- Pass a plain numeric value, e.g. --timeout 30.
- Strip units/separators from the value before passing it (parse 10s -> 10 in the script).
- For int-typed arguments, also ensure the value has no decimal part.
- Coerce in code first: Number(value) and check Number.isFinite before calling.
Example fix
// before opencli run --timeout 30s // after opencli run --timeout 30
Defensive patterns
Strategy: validation
Validate before calling
function toNumber(v: unknown, label: string): number {
const n = Number(v);
if (!Number.isFinite(n)) throw new Error(`${label} must be a valid number, got: ${String(v)}`);
return n;
}
kwargs.timeout = toNumber(kwargs.timeout, '--timeout'); Type guard
const isFiniteNumber = (v: unknown): v is number => typeof v === 'number' && Number.isFinite(v);
Try / catch
try {
await opencli.run(cmd, kwargs);
} catch (e) {
if (/must be a valid number/.test(e.message)) {
console.error(`${e.message} — strip units like 's'/'ms' and separators.`);
} else throw e;
} Prevention
- Pass bare numbers without units, underscores, commas, or locale formatting.
- Parse duration strings ('30s') into numbers before passing.
- Pre-coerce and check Number.isFinite in wrappers around the CLI.
When it happens
Trigger: Passing --retries abc, --timeout "10s", --count 1_000, or kwargs like { retries: 'fast' } to an argument typed number/int.
Common situations: Including units in the value (10s, 5ms); thousands separators or underscores; locale-formatted numbers (1,5); copying string config values into numeric flags.
Related errors
- ${label} is required
- ${label} must be a positive integer
- ${label} must be <= ${maxValue}
- ${label} must be a numeric ID
- ${label} cannot be empty
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/e7ad4a1ed84ab0df.
Report an issue: GitHub.