affaan-m/ECC · error · Error

${label} must not contain control or bidirectional formattin

Error message

${label} must not contain control or bidirectional formatting characters.

What it means

Thrown by asNonEmptyString() (via hasUnsafeControlCharacters) when the string contains C0/C1 control characters (excluding permitted whitespace in body mode) or Unicode bidirectional formatting code points (U+202A–U+202E, U+2066–U+2069). This guards against Trojans-source-style attacks and malformed paste input in memory documents.

Source

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

      || (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;
}

function validateSlug(value, label) {
  const normalized = asNonEmptyString(value, label, 64);
  if (!SLUG_PATTERN.test(normalized)) {
    throw new Error(`${label} must be a lowercase letters/numbers slug.`);
  }
  return normalized;

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Strip control and bidi characters from the input before submission (e.g. sanitize with a regex over \\u0000-\\u001F, \\u007F-\\u009F, and the bidi blocks).
  2. Re-type the value manually if paste is the suspected source.
  3. Audit the upstream producer that generated the string.

Example fix

// before
asNonEmptyString('\u202Ereversed text', 'title');
// after
const clean = value.replace(/[\\u0000-\\u001F\\u007F-\\u009F\\u202A-\\u202E\\u2066-\\u2069]/gu, '');
asNonEmptyString(clean, 'title');
Defensive patterns

Strategy: validation

Validate before calling

const UNSAFE = /[\u0000-\u001F\u007F-\u009F\u202A-\u202E\u2066-\u2069]/;
function isSafeString(value) {
  return typeof value === 'string' && !UNSAFE.test(value);
}
function stripUnsafe(value) {
  return value.replace(/[\u0000-\u001F\u007F-\u009F\u202A-\u202E\u2066-\u2069]/gu, '');
}

Type guard

function isSafeFromControlChars(value) {
  return typeof value === 'string'
    && !/[\u0000-\u001F\u007F-\u009F\u202A-\u202E\u2066-\u2069]/.test(value);
}

Try / catch

try {
  result = asNonEmptyString(value, label);
} catch (e) {
  if (/control or bidirectional/.test(e.message)) {
    const clean = value.replace(/[\u0000-\u001F\u007F-\u009F\u202A-\u202E\u2066-\u2069]/gu, '');
    result = asNonEmptyString(clean, label);
  } else throw e;
}

Prevention

When it happens

Trigger: Pasting text from a terminal or rich-text source that includes ESC, BEL, NUL, or RTL/LTR override marks; binary content leaking into a string field.

Common situations: Copy-paste from word processors or web pages that embed invisible formatting; a corrupted file; an adversarial input testing for hidden-character injection.

Related errors


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