gchq/CyberChef · error · OperationError

${this.name} must be a number.

Error message

${this.name} must be a number.

What it means

Thrown by Ingredient.validate() number checks (line 130) when the ingredient type is 'number' and checkVal is null, undefined, or NaN. This runs AFTER Ingredient.prepare() has already coerced the raw value, so by this point the value could not be parsed into a finite number.

Source

Thrown at src/core/Ingredient.mjs:130

        }

        // 2. maxLength check
        if (typeof this.maxLength === "number" && checkVal !== null && checkVal !== undefined) {
            if (typeof checkVal === "string" && checkVal.length > this.maxLength) {
                throw new OperationError(`${this.name} length cannot exceed ${this.maxLength}.`);
            }
            if (Array.isArray(checkVal) && checkVal.length > this.maxLength) {
                throw new OperationError(`${this.name} length cannot exceed ${this.maxLength}.`);
            }
            if (checkVal instanceof Uint8Array && checkVal.length > this.maxLength) {
                throw new OperationError(`${this.name} length cannot exceed ${this.maxLength}.`);
            }
        }

        // 3. number checks
        if (this.type === "number") {
            if (checkVal === null || checkVal === undefined || isNaN(checkVal)) {
                throw new OperationError(`${this.name} must be a number.`);
            }
            if (this.integer && !Number.isInteger(checkVal)) {
                throw new OperationError(`${this.name} must be an integer.`);
            }
            if (typeof this.min === "number" && checkVal < this.min) {
                throw new OperationError(`${this.name} must be greater than or equal to ${this.min}.`);
            }
            if (typeof this.max === "number" && checkVal > this.max) {
                throw new OperationError(`${this.name} must be less than or equal to ${this.max}.`);
            }
        }

        // 4. option checks
        if (this.type === "option") {
            if (Array.isArray(this.defaultValue)) {
                const permittedOptions = this.defaultValue.filter(opt => {
                    if (typeof opt !== "string") return false;
                    return !opt.match(/^\[\/?[a-z0-9 -()^]+\]$/i);

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Supply a numeric value for the ingredient in the recipe/args.
  2. Ensure the ingredient config declares a numeric defaultValue so null/undefined fall back to it.
  3. If the value comes from user text, parse it (parseFloat) before it reaches the ingredient.

Example fix

// before
op.ingValues = [null]; // number ingredient, no default

// after
op.ingValues = [16];
// or in config: { name:'Rounds', type:'number', value: 16 }
Defensive patterns

Strategy: validation

Validate before calling

function ensureNumber(name, val) {
  if (val == null || (typeof val === 'number' && isNaN(val))) {
    throw new Error(`${name} must be a number`);
  }
}

Type guard

function isFiniteNumber(v): v is number { return typeof v === 'number' && !isNaN(v); }

Try / catch

try { op.ingValues = [val]; } catch (e) { if (/must be a number/.test(e.message)) { val = defaultNumber; } }

Prevention

When it happens

Trigger: A number-typed ingredient receives null/undefined (and has no numeric default), or prepare() left it as NaN because the raw string was non-numeric and somehow reached validate (normally prepare throws first - see error 13).

Common situations: A recipe omits a required numeric arg (rounds, length, offset) and the ingredient has no default; an operation that previously had a numeric default loses it after a config edit.

Related errors


AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13). Data as JSON: /api/errors/d9a5cb56154ef1f9. Report an issue: GitHub.