{"record":{"id":"f60f1524aea332ab","repo":"avajs/ava","slug":"expected-a-number","errorCode":null,"errorMessage":"Expected a number","messagePattern":"Expected a number","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/test.js","lineNumber":419,"sourceCode":"\t\t\tfor (const log of logs) {\n\t\t\t\tthis.addLog(log);\n\t\t\t}\n\t\t}\n\n\t\tthis.refreshTimeout();\n\t\tif (this.testFailure) {\n\t\t\tthrow this.testFailure;\n\t\t}\n\t}\n\n\tsaveFirstError(error) {\n\t\tthis.assertError ??= error;\n\t\tthis.testFailure = new TestFailure();\n\t}\n\n\tplan(count, planAssertionStack) {\n\t\tif (typeof count !== 'number') {\n\t\t\tthrow new TypeError('Expected a number');\n\t\t}\n\n\t\tthis.planCount = count;\n\n\t\t// In case the `planCount` doesn't match `assertCount, we need the stack of\n\t\t// this function to throw with a useful stack.\n\t\tthis.planAssertionStack = planAssertionStack;\n\t}\n\n\ttimeout(ms, message) {\n\t\tconst result = checkAssertionMessage(message, 't.timeout()');\n\t\tif (result !== true) {\n\t\t\tthis.saveFirstError(result);\n\t\t\t// Allow the timeout to be set even when the message is invalid.\n\t\t\tmessage = '';\n\t\t}\n\n\t\tif (this.finishing) {","sourceCodeStart":401,"sourceCodeEnd":437,"githubUrl":"https://github.com/avajs/ava/blob/bbfd946322fdeca2b547a691d947fb4e18c0c67f/lib/test.js#L401-L437","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass a number literal or Number-coerced value: t.plan(3) or t.plan(Number(raw)).","Validate the source value before calling: if (typeof n !== 'number') throw ... or use Number.parseInt + Number.isFinite.","Remove t.plan() if assertion counting is not needed — planning is optional."],"exampleFix":"// before\nt.plan(process.env.PLAN_COUNT); // string -> TypeError\n\n// after\nconst count = Number.parseInt(process.env.PLAN_COUNT, 10);\nif (Number.isFinite(count)) t.plan(count);","handlingStrategy":"type-guard","validationCode":"if (typeof count !== 'number' || !Number.isInteger(count) || count < 0) throw new TypeError('t.plan() expects a non-negative integer');","typeGuard":"const isPlanCount = (v) => typeof v === 'number' && Number.isInteger(v) && v >= 0;","tryCatchPattern":"try {\n  t.plan(count);\n} catch (err) {\n  if (err instanceof TypeError && err.message === 'Expected a number') {\n    t.plan(Number(count) || 0);\n  } else throw err;\n}","preventionTips":["Coerce env/config values with Number() before t.plan()","Pass numeric literals directly where possible","Enable strict typing on wrapper helpers around t.plan"],"tags":["ava","t-plan","typeerror","assertion-count"],"backgroundTag":"invalid-argument-value","analyzedSha":"bbfd946322fdeca2b547a691d947fb4e18c0c67f","analyzedAt":"2026-09-02T01:24:43.834Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}