avajs/ava · error · TypeError

Expected a number

Error message

Expected a number

What it means

t.plan(count) sets the expected number of assertions for a test or attempt. AVA validates that the argument is a number; anything else (string, undefined, NaN-free objects, etc.) is rejected with this TypeError so assertion-count accounting stays correct.

Source

Thrown at lib/test.js:419

			for (const log of logs) {
				this.addLog(log);
			}
		}

		this.refreshTimeout();
		if (this.testFailure) {
			throw this.testFailure;
		}
	}

	saveFirstError(error) {
		this.assertError ??= error;
		this.testFailure = new TestFailure();
	}

	plan(count, planAssertionStack) {
		if (typeof count !== 'number') {
			throw new TypeError('Expected a number');
		}

		this.planCount = count;

		// In case the `planCount` doesn't match `assertCount, we need the stack of
		// this function to throw with a useful stack.
		this.planAssertionStack = planAssertionStack;
	}

	timeout(ms, message) {
		const result = checkAssertionMessage(message, 't.timeout()');
		if (result !== true) {
			this.saveFirstError(result);
			// Allow the timeout to be set even when the message is invalid.
			message = '';
		}

		if (this.finishing) {

View on GitHub (pinned to bbfd946322)

Solutions

  1. Pass a number literal or Number-coerced value: t.plan(3) or t.plan(Number(raw)).
  2. Validate the source value before calling: if (typeof n !== 'number') throw ... or use Number.parseInt + Number.isFinite.
  3. Remove t.plan() if assertion counting is not needed — planning is optional.

Example fix

// before
t.plan(process.env.PLAN_COUNT); // string -> TypeError

// after
const count = Number.parseInt(process.env.PLAN_COUNT, 10);
if (Number.isFinite(count)) t.plan(count);
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof count !== 'number' || !Number.isInteger(count) || count < 0) throw new TypeError('t.plan() expects a non-negative integer');

Type guard

const isPlanCount = (v) => typeof v === 'number' && Number.isInteger(v) && v >= 0;

Try / catch

try {
  t.plan(count);
} catch (err) {
  if (err instanceof TypeError && err.message === 'Expected a number') {
    t.plan(Number(count) || 0);
  } else throw err;
}

Prevention

When it happens

Trigger: t.plan('3'); t.plan(someVariable) where the variable is undefined; t.plan(count) where count comes from parseInt() of bad input or a config value; forwarding arguments to t.plan without validation.

Common situations: Reading the planned count from an env var or CLI arg (always a string); a helper function passing optional parameters through to t.plan; refactor changed the variable's type.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of avajs/ava@bbfd946322 (2026-09-02). Data as JSON: /api/errors/f60f1524aea332ab. Report an issue: GitHub.