affaan-m/ECC · error · Error
memory must be an object.
Error message
memory must be an object.
What it means
Thrown by normalizeMemory() as its opening guard: the memory argument must be a non-null, non-array object. Because memory has 13 named fields, anything that is not a plain object cannot satisfy the schema. Arrays are explicitly excluded even though typeof [] === 'object', and null/undefined are caught together with primitives.
Source
Thrown at scripts/lib/memory-vault-format.js:163
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',
limit: MAX_TARGETS,
validator: value => validateSlug(value, 'target harness'),
});
if (targetHarnesses.length === 0) {
throw new Error('target harnesses must contain at least one harness or "all".');
}
if (memory.schema !== MEMORY_SCHEMA_VERSION) {
throw new Error('Unsupported memory schema.');
}
return {
schema: memory.schema,
id: validateMemoryId(memory.id),View on GitHub (pinned to 01e15490f0)
Solutions
- Always build the object literal explicitly with all required fields before calling normalizeMemory.
- For inputs from JSON, validate shape first: if (!input || typeof input !== 'object' || Array.isArray(input)) return null;
- Prefer the higher-level saveMemory() helper, which constructs the object for you via normalizeSaveInput.
- Add a TypeScript input type so the mistake is a compile-time error.
Example fix
// before
const memory = JSON.parse(rawText); // could be array or primitive
return normalizeMemory(memory);
// after
const parsed = JSON.parse(rawText);
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
throw new Error('expected a memory object');
}
return normalizeMemory(parsed); Defensive patterns
Strategy: type-guard
Validate before calling
if (!input || typeof input !== 'object' || Array.isArray(input)) {
throw new TypeError('memory must be a plain object');
}
normalizeMemory(input); Type guard
function isMemoryObject(value): value is Record<string, unknown> {
return value !== null && typeof value === 'object' && !Array.isArray(value);
} Prevention
- Prefer saveMemory() over normalizeMemory() — it builds the object for you.
- Type the input as a specific interface, not 'any'.
- Validate shape after JSON.parse() before passing into the library.
When it happens
Trigger: normalizeMemory(null), normalizeMemory(undefined) from a lookup that returned nothing, normalizeMemory([]) when the caller forgot to destructure an array of memories, normalizeMemory(JSON.parse('"string"')) where JSON.parse returned a primitive, or normalizeMemory(42) from a numeric ID confusion.
Common situations: Reading from a JSON file whose top-level shape is an array rather than an object. Calling normalizeMemory(saveMemoryInput) inside a loop where one iteration forgot to build the object. Network deserialiser returning a string instead of an object on error.
Related errors
- memory body must be a string.
- Memory roots must include a trusted boundary policy.
- ${label} must be a non-empty string.
- ${label} is too long (maximum ${maxChars} characters).
- ${label} must not contain control or bidirectional formattin
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/437fec94758fd1a2.
Report an issue: GitHub.