affaan-m/ECC · error · Error

${label} must not contain duplicate values.

Error message

${label} must not contain duplicate values.

What it means

Thrown by uniqueStrings() when two entries in the input array normalize to the same value (the validator is applied before the duplicate check). It enforces a set semantic for list fields so storage and lookup are deterministic.

Source

Thrown at scripts/lib/memory-vault-format.js:125

function validateMemoryId(value) {
  const normalized = asNonEmptyString(value, 'memory id', 132);
  if (!MEMORY_ID_PATTERN.test(normalized)) {
    throw new Error('memory id must match mem_<lowercase-id> and cannot contain a path.');
  }
  return normalized;
}

function uniqueStrings(values, { label, limit, validator }) {
  if (!Array.isArray(values)) {
    throw new Error(`${label} must be an array.`);
  }
  if (values.length > limit) {
    throw new Error(`${label} has too many values (maximum ${limit}).`);
  }
  return values.reduce((result, value) => {
    const normalized = validator(value);
    if (result.includes(normalized)) {
      throw new Error(`${label} must not contain duplicate values.`);
    }
    return [...result, normalized];
  }, []);
}

function validateTimestamp(value, label) {
  const normalized = asNonEmptyString(value, label, 64);
  const parsed = new Date(normalized);
  if (
    !ISO_TIMESTAMP_PATTERN.test(normalized)
    || Number.isNaN(parsed.getTime())
    || parsed.toISOString() !== normalized
  ) {
    throw new Error(`${label} must be an ISO-8601 timestamp.`);
  }
  return normalized;
}

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Dedupe the array (e.g. [...new Set(values)]) before passing it in.
  2. Remember the validator may normalize (lowercase, trim) before the duplicate check runs.
  3. Audit the upstream producer if duplicates keep appearing.

Example fix

// before
uniqueStrings(['api', 'api', 'auth'], { label: 'tags', limit: 32, validator: v => v.toLowerCase() });
// after
uniqueStrings([...new Set(['api', 'api', 'auth'])], { label: 'tags', limit: 32, validator: v => v.toLowerCase() });
Defensive patterns

Strategy: validation

Validate before calling

function dedupe(values) {
  return [...new Set(values)];
}
// pass deduped array to uniqueStrings to avoid the duplicate guard firing:
result = uniqueStrings(dedupe(values), opts);

Type guard

function hasNoDuplicates(values) {
  return Array.isArray(values) && new Set(values).size === values.length;
}

Try / catch

try {
  result = uniqueStrings(values, opts);
} catch (e) {
  if (/must not contain duplicate values/.test(e.message)) {
    result = uniqueStrings([...new Set(values)], opts);
  } else throw e;
}

Prevention

When it happens

Trigger: Passing ['tag-a', 'tag-a'], ['TAG-A', 'tag-a'] when the validator lowercases, or two slugs that trim to the same value.

Common situations: Merging tag lists from multiple sources without dedup; case-sensitive copy-paste that produces near-duplicates after normalization.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/7af48005559c46eb. Report an issue: GitHub.