denoland/deno · error · TypeError

ERR_INVALID_ARG_VALUE

ERR_INVALID_ARG_VALUE

Error message

The property 'options.tags[${i}]' must not be an empty string. Received ${tag}

What it means

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.

Source

Thrown at ext/node/polyfills/testing.ts:1888

}

// Node's experimental test `tags` feature. Tags are validated (array of
// non-empty strings), canonicalized (lowercased and deduped, preserving
// declaration order), and the experimental warning is emitted once the first
// time any tag is registered.
let tagsWarningEmitted = false;
function prepareTags(tags, argName) {
  if (!ArrayIsArray(tags)) {
    throw new ERR_INVALID_ARG_TYPE(argName, "string[]", tags);
  }
  const canonical = [];
  for (let i = 0; i < tags.length; i++) {
    const tag = tags[i];
    if (typeof tag !== "string") {
      throw new ERR_INVALID_ARG_TYPE(`${argName}[${i}]`, "string", tag);
    }
    if (tag === "") {
      throw new ERR_INVALID_ARG_VALUE(
        `${argName}[${i}]`,
        tag,
        "must not be an empty string",
      );
    }
    const lower = StringPrototypeToLowerCase(tag);
    if (!ArrayPrototypeIncludes(canonical, lower)) {
      ArrayPrototypePush(canonical, lower);
    }
  }
  if (canonical.length > 0 && !tagsWarningEmitted) {
    tagsWarningEmitted = true;
    emitExperimentalWarning("Test tags");
  }
  return canonical;
}

function prepareOptions(name, options, fn, overrides) {

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Filter empties when splitting: input.split(',').map((s) => s.trim()).filter((s) => s !== '')
  2. Remove placeholder empty strings from the literal array
  3. Default to no tags option at all when the computed list is empty

Example fix

// before
const tags = process.env.TAGS.split(','); // 'smoke,' -> ['smoke', '']
test('x', { tags }, fn);

// after
const tags = process.env.TAGS.split(',').map((s) => s.trim()).filter(Boolean);
if (tags.length > 0) {
  test('x', { tags }, fn);
} else {
  test('x', fn);
}
Defensive patterns

Strategy: validation

Validate before calling

function parseTags(input) {
  return input
    .split(',')
    .map((s) => s.trim().toLowerCase())
    .filter((s) => s !== '');
}

const tags = parseTags(process.env.TAGS ?? '');
test('x', tags.length > 0 ? { tags } : {}, fn);

Type guard

const hasNoEmptyTags = (v) =>
  Array.isArray(v) && v.every((t) => typeof t === 'string' && t.length > 0);

Prevention

When it happens

Trigger: 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.

Common situations: Comma-splitting CLI/env tag input without filtering empties; templated tag lists where a variable was never filled in.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/e0719489e7cc89d0. Report an issue: GitHub.