{"record":{"id":"2935e60c1499653d","repo":"affaan-m/ECC","slug":"memory-body-must-be-a-string","errorCode":null,"errorMessage":"memory body must be a string.","messagePattern":"memory body must be a string\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/memory-vault-format.js","lineNumber":146,"sourceCode":"  }, []);\n}\n\nfunction validateTimestamp(value, label) {\n  const normalized = asNonEmptyString(value, label, 64);\n  const parsed = new Date(normalized);\n  if (\n    !ISO_TIMESTAMP_PATTERN.test(normalized)\n    || Number.isNaN(parsed.getTime())\n    || parsed.toISOString() !== normalized\n  ) {\n    throw new Error(`${label} must be an ISO-8601 timestamp.`);\n  }\n  return normalized;\n}\n\nfunction normalizeBody(value) {\n  if (typeof value !== 'string') {\n    throw new Error('memory body must be a string.');\n  }\n  if (hasUnsafeControlCharacters(value, true)) {\n    throw new Error('memory body must not contain unsafe control or bidirectional formatting characters.');\n  }\n  const normalized = value.trim();\n  if (normalized.length === 0) {\n    throw new Error('memory body must contain non-whitespace context.');\n  }\n  if (Buffer.byteLength(normalized, 'utf8') > MAX_BODY_BYTES) {\n    throw new Error(`memory body is too large (maximum ${MAX_BODY_BYTES} bytes).`);\n  }\n  return normalized;\n}\n\nfunction normalizeMemory(memory) {\n  if (!memory || typeof memory !== 'object' || Array.isArray(memory)) {\n    throw new Error('memory must be an object.');\n  }","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/memory-vault-format.js#L128-L164","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nnormalizeMemory({ body: fs.readFileSync(p), ... })\n// after\nnormalizeMemory({ body: fs.readFileSync(p, 'utf8'), ... })","handlingStrategy":"type-guard","validationCode":"if (typeof body !== 'string') body = typeof body === 'object' && body !== null && 'text' in body ? String(body.text) : String(body ?? '');","typeGuard":"const isString = (v) => typeof v === 'string';","tryCatchPattern":"try { normalizeMemory(mem); } catch (e) { if (e.message === 'memory body must be a string.') { mem.body = String(mem.body); } else throw e; }","preventionTips":["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"],"tags":["validation","type-mismatch","memory-vault"],"backgroundTag":"type-mismatch","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}