affaan-m/ECC · error
memory body must be a string.
Error message
memory body must be a string.
What it means
normalizeBody requires the memory body to be a JavaScript string before any other processing. The library throws this when the body field is any other type, because all subsequent checks (control characters, trimming, byte-size limits) are string operations.
Solutions
- Coerce with String(value) if the value is a known scalar, or buffer.toString('utf8') for Buffers.
- Fix the producer so it always assigns a string to the body field.
- If the body may be absent, decide the default (e.g. '') before calling — but note an empty/whitespace-only body is rejected separately.
- Unwrap nested objects: obj.text -> obj.text instead of passing obj.
Example fix
// before
normalizeMemory({ body: fs.readFileSync(p), ... })
// after
normalizeMemory({ body: fs.readFileSync(p, 'utf8'), ... }) Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof body !== 'string') body = typeof body === 'object' && body !== null && 'text' in body ? String(body.text) : String(body ?? '');
Type guard
const isString = (v) => typeof v === 'string';
Try / catch
try { normalizeMemory(mem); } catch (e) { if (e.message === 'memory body must be a string.') { mem.body = String(mem.body); } else throw e; } Prevention
- Read files with the 'utf8' encoding option instead of passing Buffers
- Type body as string in the memory document interface
- Unwrap nested {text} objects at the producer
- Log typeof body when a save fails to catch silent undefined
When it happens
Trigger: Calling normalizeMemory with body set to null, undefined, a number, a boolean, an object {text: '...'}, an array of strings/lines, or a Buffer from a file read.
Common situations: Loading the body from JSON where the field was accidentally nested; passing a file's raw Buffer instead of buffer.toString('utf8'); a template/function result returning undefined on some code path; YAML frontmatter parsed with a numeric-looking body.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- must be an array.
- Canonical session snapshot must be an object
- Canonical session snapshot requires
- Canonical session snapshot requires
- Canonical session snapshot requires
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/2935e60c1499653d.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/memory-vault-format.js:146
}, []);
}
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.');
}View on GitHub (pinned to 8321021c54)