{"record":{"id":"e0719489e7cc89d0","repo":"denoland/deno","slug":"err-invalid-arg-value-e07194","errorCode":"ERR_INVALID_ARG_VALUE","errorMessage":"The property 'options.tags[${i}]' must not be an empty string. Received ${tag}","messagePattern":"The property 'options\\.tags\\[(.+?)\\]' must not be an empty string\\. Received (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/testing.ts","lineNumber":1888,"sourceCode":"}\n\n// Node's experimental test `tags` feature. Tags are validated (array of\n// non-empty strings), canonicalized (lowercased and deduped, preserving\n// declaration order), and the experimental warning is emitted once the first\n// time any tag is registered.\nlet tagsWarningEmitted = false;\nfunction prepareTags(tags, argName) {\n  if (!ArrayIsArray(tags)) {\n    throw new ERR_INVALID_ARG_TYPE(argName, \"string[]\", tags);\n  }\n  const canonical = [];\n  for (let i = 0; i < tags.length; i++) {\n    const tag = tags[i];\n    if (typeof tag !== \"string\") {\n      throw new ERR_INVALID_ARG_TYPE(`${argName}[${i}]`, \"string\", tag);\n    }\n    if (tag === \"\") {\n      throw new ERR_INVALID_ARG_VALUE(\n        `${argName}[${i}]`,\n        tag,\n        \"must not be an empty string\",\n      );\n    }\n    const lower = StringPrototypeToLowerCase(tag);\n    if (!ArrayPrototypeIncludes(canonical, lower)) {\n      ArrayPrototypePush(canonical, lower);\n    }\n  }\n  if (canonical.length > 0 && !tagsWarningEmitted) {\n    tagsWarningEmitted = true;\n    emitExperimentalWarning(\"Test tags\");\n  }\n  return canonical;\n}\n\nfunction prepareOptions(name, options, fn, overrides) {","sourceCodeStart":1870,"sourceCodeEnd":1906,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/testing.ts#L1870-L1906","documentation":"prepareTags() rejects empty strings as tag values: after type-checking each element of options.tags, an empty string throws ERR_INVALID_ARG_VALUE stating the property 'must not be an empty string'. This keeps tags meaningful as filter keys, since testTagFilters matching would be ambiguous with '' present.","triggerScenarios":"test('x', { tags: ['smoke', ''] }, fn); tags built by splitting a comma-joined string that had a trailing comma ('smoke,').split(',') yielding an empty final element; placeholder '' for an unimplemented tag.","commonSituations":"Comma-splitting CLI/env tag input without filtering empties; templated tag lists where a variable was never filled in.","solutions":["Filter empties when splitting: input.split(',').map((s) => s.trim()).filter((s) => s !== '')","Remove placeholder empty strings from the literal array","Default to no tags option at all when the computed list is empty"],"exampleFix":"// before\nconst tags = process.env.TAGS.split(','); // 'smoke,' -> ['smoke', '']\ntest('x', { tags }, fn);\n\n// after\nconst tags = process.env.TAGS.split(',').map((s) => s.trim()).filter(Boolean);\nif (tags.length > 0) {\n  test('x', { tags }, fn);\n} else {\n  test('x', fn);\n}","handlingStrategy":"validation","validationCode":"function parseTags(input) {\n  return input\n    .split(',')\n    .map((s) => s.trim().toLowerCase())\n    .filter((s) => s !== '');\n}\n\nconst tags = parseTags(process.env.TAGS ?? '');\ntest('x', tags.length > 0 ? { tags } : {}, fn);","typeGuard":"const hasNoEmptyTags = (v) =>\n  Array.isArray(v) && v.every((t) => typeof t === 'string' && t.length > 0);","tryCatchPattern":null,"preventionTips":["Filter(Boolean) after splitting comma-joined tag strings","Remove placeholder '' entries from tag literals","Skip the tags option entirely when the computed list is empty"],"tags":["node-test","test-tags","argument-validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-21T10:36:37.832Z"}