affaan-m/ECC · error

must be a non-empty string.

Error message

${label} must be a non-empty string.

What it means

asNonEmptyString is the shared validator in the memory-vault format layer. Every labeled field (title, content, etc.) must be a string that is non-empty after trimming; anything else — non-strings, whitespace-only values — is rejected with a message naming the field via the label parameter.

Solutions

  1. Supply a non-empty string for the labeled field before calling.
  2. Trim-check the input in the UI/CLI layer and prompt again when blank.
  3. Fall back to a sensible default for optional fields instead of passing undefined.
  4. Ensure values read from JSON are strings, not null.

Example fix

// before
normalizeMemory({ title: req.body.title })  // title: undefined
// after
normalizeMemory({ title: (req.body.title || '').trim() || 'Untitled' })
Defensive patterns

Strategy: validation

Validate before calling

function requireNonEmptyString(v, fallback) {
  const s = typeof v === 'string' ? v.trim() : ''
  if (!s) return fallback ?? (() => { throw new Error('Field is required') })()
  return s
}

Type guard

function isNonEmptyString(v) {
  return typeof v === 'string' && v.trim().length > 0
}
if (!isNonEmptyString(input.title)) throw new TypeError('title must be a non-empty string')

Try / catch

try {
  const memory = normalizeMemory(raw)
} catch (err) {
  if (err.message.endsWith('must be a non-empty string.')) {
    console.error(`Missing field: ${err.message.split(' ')[0]} — prompt the user or apply a default`)
  } else throw err
}

Prevention

When it happens

Trigger: Calling asNonEmptyString(value, label) (directly or via normalizeMemory/resolveOverride) with undefined, null, a number, or a string like ' ' whose trim().length is 0.

Common situations: A memory record saved with an empty title/content field; JSON round-trips turning a value into null; form or CLI input left blank; an optional field assumed to have a default but actually undefined.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/6035cf848a6f7cab. Report an issue: GitHub.

Appendix: source

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

function hasUnsafeControlCharacters(value, allowBodyWhitespace = false) {
  return Array.from(value).some(character => {
    const codePoint = character.codePointAt(0);
    const allowedWhitespace = allowBodyWhitespace
      && (codePoint === 0x09 || codePoint === 0x0a || codePoint === 0x0d);
    const isControl = (codePoint <= 0x1f && !allowedWhitespace)
      || (codePoint >= 0x7f && codePoint <= 0x9f);
    const isBidirectionalFormatting = (
      (codePoint >= 0x202a && codePoint <= 0x202e)
      || (codePoint >= 0x2066 && codePoint <= 0x2069)
    );
    return isControl || isBidirectionalFormatting;
  });
}

function asNonEmptyString(value, label, maxChars = 10_000) {
  if (typeof value !== 'string' || value.trim().length === 0) {
    throw new Error(`${label} must be a non-empty string.`);
  }
  const normalized = value.trim();
  if (normalized.length > maxChars) {
    throw new Error(`${label} is too long (maximum ${maxChars} characters).`);
  }
  if (hasUnsafeControlCharacters(normalized)) {
    throw new Error(`${label} must not contain control or bidirectional formatting characters.`);
  }
  return normalized;
}

function validateEnum(value, allowed, label) {
  const normalized = asNonEmptyString(value, label, 64);
  if (!allowed.includes(normalized)) {
    throw new Error(`${label} must be one of: ${allowed.join(', ')}.`);
  }
  return normalized;
}

View on GitHub (pinned to 8321021c54)