{"record":{"id":"4488336a226222f2","repo":"avajs/ava","slug":"test-hook-titles-must-be-strings","errorCode":null,"errorMessage":"Test & hook titles must be strings","messagePattern":"Test & hook titles must be strings","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/runner.js","lineNumber":135,"sourceCode":"\t\t\t\t}\n\n\t\t\t\t// --match selects TODO tests.\n\t\t\t\tmetadata.selected &&= isTitleMatch(title.value, this.matchPatterns);\n\n\t\t\t\tthis.tasks.todo.push({title: title.value, metadata});\n\t\t\t\tthis.emit('stateChange', {\n\t\t\t\t\ttype: 'declared-test',\n\t\t\t\t\ttitle: title.value,\n\t\t\t\t\tknownFailing: false,\n\t\t\t\t\ttodo: true,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tif (typeof implementation !== 'function') {\n\t\t\t\t\tthrow new TypeError('Expected an implementation. Use `test.todo()` for tests without an implementation.');\n\t\t\t\t}\n\n\t\t\t\tif (title.isSet && !title.isValid) {\n\t\t\t\t\tthrow new TypeError('Test & hook titles must be strings');\n\t\t\t\t}\n\n\t\t\t\tlet fallbackTitle = title.value;\n\t\t\t\tif (title.isEmpty) {\n\t\t\t\t\tif (metadata.type === 'test') {\n\t\t\t\t\t\tthrow new TypeError('Tests must have a title');\n\t\t\t\t\t} else if (metadata.always) {\n\t\t\t\t\t\tfallbackTitle = `${metadata.type}.always hook`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfallbackTitle = `${metadata.type} hook`;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (metadata.type === 'test' && !this.registerUniqueTitle(title.value)) {\n\t\t\t\t\tthrow new Error(`Duplicate test title: ${title.value}`);\n\t\t\t\t}\n\n\t\t\t\tconst task = {","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/avajs/ava/blob/bbfd946322fdeca2b547a691d947fb4e18c0c67f/lib/runner.js#L117-L153","documentation":"AVA validates that any explicitly provided test or hook title is a string. parseTestArgs sets title.isValid only when the value is a string; if a title was supplied but is not a string (number, object, null, template returning non-string, etc.), the constructor throws this TypeError. Titles are used as identifiers for snapshots, --match, and reporting, so they must be strings.","triggerScenarios":"test(42, fn), test({a: 1}, fn), test(null, fn), or calling an assertion-style API like t => {} with a non-string title variable, e.g. test(myTitle, fn) where myTitle is a number or undefined-but-set value.","commonSituations":"Passing a numeric constant or enum as the title; a variable title that is undefined at runtime but was 'set' via destructuring; migrating code where the title was accidentally dropped into the implementation slot; template literals are fine, but null/undefined variables are not.","solutions":["Make the title a string: wrap with String(...) or use a template literal","Fix the title variable so it holds a real string at call time","Move a mistakenly placed implementation argument to its correct position in the call","Log typeof title just before the call to find where the non-string comes from"],"exampleFix":"// before\nconst id = 42;\ntest(id, t => { ... });\n\n// after\ntest(`test ${id}`, t => { ... });","handlingStrategy":"type-guard","validationCode":"if (title !== undefined && typeof title !== 'string') {\n\tthrow new TypeError('Test titles must be strings');\n}\ntest(title, fn);","typeGuard":"function isValidTitle(title) {\n\treturn title === undefined || typeof title === 'string';\n}","tryCatchPattern":"try {\n\ttest(title, fn);\n} catch (err) {\n\tif (err.message === 'Test & hook titles must be strings') {\n\t\ttest(String(title), fn); // coerce and retry declaration\n\t} else {\n\t\tthrow err;\n\t}\n}","preventionTips":["Wrap dynamic titles in template literals to guarantee string type","Check typeof of title variables before declaring tests","Avoid passing numbers, enums, or objects directly as titles","Enable TypeScript so non-string titles are caught at compile time"],"tags":["ava","title-type","typeerror","api-misuse"],"backgroundTag":"invalid-argument-value","analyzedSha":"bbfd946322fdeca2b547a691d947fb4e18c0c67f","analyzedAt":"2026-09-02T01:24:43.834Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}