{"id":"29ad35dfd304784b","repo":"jestjs/jest","slug":"each-must-only-be-called-with-an-array-or-tagge","errorCode":null,"errorMessage":"`.each` must only be called with an Array or Tagged Template Literal.","messagePattern":"`\\.each` must only be called with an Array or Tagged Template Literal\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/jest-each/src/index.ts","lineNumber":21,"sourceCode":" *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport type {Global} from '@jest/types';\nimport bind from './bind';\n\ntype Global = Global.Global;\nconst install = (\n  g: Global,\n  table: Global.EachTable,\n  ...data: Global.TemplateData\n) => {\n  const bindingWithArray = data.length === 0;\n  const bindingWithTemplate = Array.isArray(table) && !!(table as any).raw;\n  if (!bindingWithArray && !bindingWithTemplate) {\n    throw new Error(\n      '`.each` must only be called with an Array or Tagged Template Literal.',\n    );\n  }\n  const test = (\n    title: string,\n    test: Global.EachTestFn<Global.TestFn>,\n    timeout?: number,\n  ) => bind(g.test)(table, ...data)(title, test, timeout);\n  test.skip = bind(g.test.skip)(table, ...data);\n  test.only = bind(g.test.only)(table, ...data);\n\n  const testConcurrent = (\n    title: string,\n    test: Global.EachTestFn<Global.TestFn>,\n    timeout?: number,\n  ) => bind(g.test.concurrent)(table, ...data)(title, test, timeout);\n\n  test.concurrent = testConcurrent;","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/jestjs/jest/blob/f49721c78e195558b40913977c9230f5b7f559d8/packages/jest-each/src/index.ts#L3-L39","documentation":"The `install` helper in jest-each requires `.each` to be invoked with either a plain Array or a Tagged Template Literal. `bindingWithArray` is true when no extra template data is passed, and `bindingWithTemplate` requires the value to be an Array carrying a `.raw` property (the shape of a tagged template). If neither holds, the call is ambiguous and jest-each refuses to bind at index.ts:21.","triggerScenarios":"Calling `describe.each(42)(...)`, `.each(someObject)(...)`, `.each(myFunction)(...)`, or `.each('plain string')(...)` — anything that is not an array and not a tagged template expression.","commonSituations":"Passing a single primitive where an array was intended (`each(1)` instead of `each([1])`); passing a Map/Set/Object expecting spread semantics; refactoring that drops the array wrapper; using a generator/iterator directly.","solutions":["Wrap the value in an array: `.each([value])`.","If using a table object, convert to an array of row arrays first.","For a tagged-template table, use the backtick call form: `.each\\`head | val\\n${row1}\\`` rather than `.each(string)`.","Double-check you are calling `.each` (table) then `(title, fn)`, not collapsing the two calls."],"exampleFix":"// before\ndescribe.each(myObject)('case %s', (row) => {});\n\n// after\ndescribe.each(Object.values(myObject))('case %j', (row) => {});","handlingStrategy":"type-guard","validationCode":"// wrap .each so misuse is caught with a clear message before binding\nfunction safeEach(table) {\n  const isArr = Array.isArray(table);\n  const isTpl = isArr && Object.prototype.hasOwnProperty.call(table, 'raw');\n  if (!isArr && !(isArr && isTpl)) throw new TypeError('each() needs Array or tagged template');\n  return realEach(table);\n}","typeGuard":"const isEachTable = (t: unknown): t is unknown[] | TemplateStringsArray => Array.isArray(t);","tryCatchPattern":null,"preventionTips":["Always wrap values in an array literal.","Enable @typescript-eslint rules that flag non-array arguments to .each.","Lint test files for .each calls without array/template syntax."],"tags":["jest-each","parameterized-tests","validation"],"analyzedSha":"f49721c78e195558b40913977c9230f5b7f559d8","analyzedAt":"2026-08-03T20:16:28.571Z","schemaVersion":2}