{"record":{"id":"4165e0f4b8bedcfc","repo":"koala73/worldmonitor","slug":"supply-test-files-or-globs","errorCode":null,"errorMessage":"Supply test files or globs","messagePattern":"Supply test files or globs","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/run-data-tests.mjs","lineNumber":53,"sourceCode":"      list: { type: 'boolean', default: false },\n      timings: { type: 'string' },\n      'test-name-pattern': { type: 'string' },\n    },\n  });\n  if (!/^[1-9]\\d*$/.test(values.concurrency) || !Number.isSafeInteger(Number(values.concurrency))) {\n    throw new Error('Concurrency must be a positive integer');\n  }\n  let index = 1;\n  let total = 1;\n  if (values.shard) {\n    const match = /^([1-9]\\d*)\\/([1-9]\\d*)$/.exec(values.shard);\n    if (!match) throw new Error('Shard must be INDEX/TOTAL (for example 1/2)');\n    [index, total] = match.slice(1).map(Number);\n    if (!Number.isSafeInteger(index) || !Number.isSafeInteger(total) || index > total) {\n      throw new Error('Shard index must be between 1 and TOTAL');\n    }\n  }\n  if (!positionals.length) throw new Error('Supply test files or globs');\n  const files = [...new Set(positionals.flatMap((pattern) => {\n    const matches = (existsSync(pattern) && statSync(pattern).isFile() ? [pattern] : globSync(pattern))\n      .map((file) => file.split(sep).join('/'));\n    if (!matches.length) throw new Error(`No test files match ${pattern}`);\n    return matches;\n  }))];\n  const durations = JSON.parse(readFileSync(timingPath, 'utf8'));\n  if (total > files.length) throw new Error('Shard count exceeds the test file count');\n  const selected = partitionTests(files, durations, total)[index - 1];\n  if (!selected.length) throw new Error('The selected shard contains no test files');\n  if (values.list) {\n    console.log(JSON.stringify(selected));\n    return 0;\n  }\n  console.log(`Data tests: ${selected.length}/${files.length} files, shard ${index}/${total}, concurrency ${values.concurrency}`);\n  const env = { ...process.env };\n  // This is a new test run, even when a contract test invokes the CLI.\n  delete env.NODE_TEST_CONTEXT;","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/scripts/run-data-tests.mjs#L35-L71","documentation":"scripts/run-data-tests.mjs is a CLI runner for data test files that supports sharding. After parsing the --shard INDEX/TOTAL option it validates that at least one test file or glob was passed as a positional argument; if none were, it throws 'Supply test files or globs'. It is a usage guard against invoking the runner with sharding options but no files to run.","triggerScenarios":"Running `node scripts/run-data-tests.mjs` (optionally with --shard, --list, --concurrency, etc.) without any positional file or glob arguments, e.g. `node scripts/run-data-tests.mjs --shard 1/2`.","commonSituations":"CI workflow steps that build the file list in a variable which ends up empty (e.g. `node scripts/run-data-tests.mjs $FILES` with FILES=''); copy-pasting a documented command with the file list placeholder never filled; a wrapper script dropping positional args when forwarding flags.","solutions":["Pass at least one test file or glob as a positional argument, e.g. `node scripts/run-data-tests.mjs 'tests/**/*.test.mjs'`","Check the CI step or wrapper for an unexpanded/empty variable holding the file list","Run `node scripts/run-data-tests.mjs --help` (or read the script header) to confirm expected usage"],"exampleFix":"// before\nnode scripts/run-data-tests.mjs --shard 1/2\n// after\nnode scripts/run-data-tests.mjs --shard 1/2 'tests/data/**/*.test.mjs'","handlingStrategy":"validation","validationCode":"const args = process.argv.slice(2).filter(a => !a.startsWith('--'));\nif (args.length === 0) {\n  console.error('Usage: node scripts/run-data-tests.mjs [--shard N/T] <files...|globs...>');\n  process.exit(2);\n}","typeGuard":"const hasPositionals = (argv) => argv.some(a => !a.startsWith('--'));","tryCatchPattern":"try {\n  await main();\n} catch (err) {\n  if (err.message === 'Supply test files or globs') {\n    console.error('Usage: node scripts/run-data-tests.mjs [--shard N/T] <files|globs>');\n    process.exit(2);\n  }\n  throw err;\n}","preventionTips":["Always include at least one file or glob in the command, even when only tweaking flags","In CI, guard against empty variables: `node scripts/run-data-tests.mjs ${FILES:?FILES not set}`","Verify empty-string positionals are filtered or rejected before invoking the runner"],"tags":["cli","argument-validation","test-runner"],"backgroundTag":"missing-cli-argument","analyzedSha":"7d06c8633d256c18e38133030bc3613976a96ec9","analyzedAt":"2026-09-15T16:44:39.439Z","contentChangedAt":"2026-09-15T16:44:39.439Z","schemaVersion":2},"datasetVersion":"2026-09-15T18:17:12.389Z"}