affaan-m/ECC · error · Error

memory body must not contain unsafe control or…

Error message

memory body must not contain unsafe control or bidirectional formatting characters.

What it means

normalizeBody rejects bodies containing control characters (except tab, LF, CR) or Unicode bidirectional-formatting code points (U+202A–U+202E, U+2066–U+2069). This guards against corrupted content and Trojan-Source-style bidirectional attacks that can make code/text render deceptively in the vault.

Solutions

  1. Strip unsafe characters before calling: remove /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F\u202A-\u202E\u2066-\u2069]/g from the string.
  2. Replace ANSI terminal escape sequences with a regex like /\x1b\[[0-9;]*m/g before storing.
  3. Retype or re-export the content from a plain-text editor if it came from a copy/paste with hidden bidi marks.
  4. Remove a leading UTF-8 BOM (\uFEFF is not in the rejected ranges, but adjacent control bytes often are) and re-check.

Example fix

// before
normalizeMemory({ body: rawTerminalOutput, ... })
// after
const clean = rawTerminalOutput.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F\u202A-\u202E\u2066-\u2069]/g, '');
normalizeMemory({ body: clean, ... })
Defensive patterns

Strategy: validation

Validate before calling

const stripUnsafe = (s) => s.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F\u202A-\u202E\u2066-\u2069]/g, '');
body = stripUnsafe(body);

Type guard

const hasUnsafeChars = (s) => /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F\u202A-\u202E\u2066-\u2069]/.test(s);

Try / catch

try { normalizeMemory(mem); } catch (e) { if (e.message.includes('unsafe control or bidirectional')) { mem.body = stripUnsafe(mem.body); } else throw e; }

Prevention

When it happens

Trigger: Calling normalizeMemory with a body containing NUL bytes, ANSI escape sequences, C1 control characters, or invisible RTL/LTR override marks — typically from binary-ish input, terminal-captured output, or copied text with hidden bidi characters.

Common situations: Pasting text from terminals, PDFs, or chat apps that embed invisible formatting characters; logging raw process output that includes ANSI color codes; mixed LTR/RTL content copied from bilingual editors; files edited in a tool that inserted BOM/control bytes.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

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

function normalizeBody(value) {
  if (typeof value !== 'string') {
    throw new Error('memory body must be a string.');
  }
  if (hasUnsafeControlCharacters(value, true)) {
    throw new Error('memory body must not contain unsafe control or bidirectional formatting characters.');
  }
  const normalized = value.trim();
  if (normalized.length === 0) {
    throw new Error('memory body must contain non-whitespace context.');
  }
  if (Buffer.byteLength(normalized, 'utf8') > MAX_BODY_BYTES) {
    throw new Error(`memory body is too large (maximum ${MAX_BODY_BYTES} bytes).`);
  }
  return normalized;
}

function normalizeMemory(memory) {
  if (!memory || typeof memory !== 'object' || Array.isArray(memory)) {
    throw new Error('memory must be an object.');
  }

  const targetHarnesses = uniqueStrings(memory.targetHarnesses, {
    label: 'target harnesses',

View on GitHub (pinned to 8321021c54)