{"record":{"id":"f08cd8585b671ea7","repo":"koala73/worldmonitor","slug":"shard-count-exceeds-the-test-file-count","errorCode":null,"errorMessage":"Shard count exceeds the test file count","messagePattern":"Shard count exceeds the test file count","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/run-data-tests.mjs","lineNumber":61,"sourceCode":"  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;\n  const timingFd = values.timings ? openSync(values.timings, 'w') : undefined;\n  let success = false;\n  try {\n    const events = run({\n      files: selected.map((file) => resolve(file)),\n      concurrency: Number(values.concurrency),\n      timeout: 120000,\n      execArgv: ['--import', 'tsx'],","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/scripts/run-data-tests.mjs#L43-L79","documentation":"When --shard N/T is given, the runner partitions the resolved test files into t shards. If the requested total shard count t exceeds the number of resolved test files, some shards would be empty by construction, so it throws 'Shard count exceeds the test file count' to abort the run.","triggerScenarios":"Running `node scripts/run-data-tests.mjs --shard 4/8 <globs>` where the globs resolve to fewer than 8 files, e.g. passing 5 files with `--shard 1/8`.","commonSituations":"Bumping CI matrix parallelism without shrinking the file list; narrowing the test globs (fewer files) while the CI matrix still requests more shards; a --shard TOTAL left at an old larger value after test files were removed.","solutions":["Lower the TOTAL in --shard to at most the number of matched files, e.g. --shard 1/5 for 5 files","Add more files/globs so the count meets or exceeds the shard total","Check which files the current globs resolve to and reconcile with the CI matrix shard count"],"exampleFix":"// before (3 files resolved)\nnode scripts/run-data-tests.mjs --shard 2/8 'tests/data/**/*.test.mjs'\n// after\nnode scripts/run-data-tests.mjs --shard 2/3 'tests/data/**/*.test.mjs'","handlingStrategy":"validation","validationCode":"import { globSync } from 'node:fs';\nconst fileCount = new Set(globs.flatMap(g => globSync(g))).size;\nif (shardTotal > fileCount) {\n  throw new Error(`--shard TOTAL (${shardTotal}) exceeds ${fileCount} resolved test files`);\n}","typeGuard":"const shardCountIsValid = (total, files) => Number.isSafeInteger(total) && total >= 1 && total <= files.length;","tryCatchPattern":"try {\n  await run();\n} catch (err) {\n  if (err.message === 'Shard count exceeds the test file count') {\n    console.error(`Reduce --shard TOTAL to <= number of matched files (matched: ${files.length}).`);\n    process.exit(2);\n  }\n  throw err;\n}","preventionTips":["Derive the CI matrix shard count from the same glob the runner uses, or cap TOTAL dynamically","When removing test files, audit shard TOTAL values in CI matrix configs","Keep one source of truth for the file globs shared between the matrix definition and the runner invocation"],"tags":["cli","sharding","config","test-runner"],"backgroundTag":"invalid-config-value","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"}