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
- Strip unsafe characters before calling: remove /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F\u202A-\u202E\u2066-\u2069]/g from the string.
- Replace ANSI terminal escape sequences with a regex like /\x1b\[[0-9;]*m/g before storing.
- Retype or re-export the content from a plain-text editor if it came from a copy/paste with hidden bidi marks.
- 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
- Sanitize any text captured from terminals (strip ANSI escapes)
- Beware copy/paste from PDFs and chat apps carrying hidden bidi marks
- Run a Trojan-Source scan on pasted code snippets
- Store text as UTF-8 and re-encode once before validating
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
- must not contain control or bidirectional formatting…
- Refusing to save memory containing a suspected secret
- artifact path escapes output directory
- artifact permits provider execution
- download requires HTTPS on an approved fal.media host
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)