{"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":"validation","errorClass":"Error","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/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/memory-vault-format.js#L128-L164","documentation":"Thrown by normalizeBody() as its very first check: memory.body must be typeof 'string'. The body field is the human-readable context of a memory entry; non-string values (numbers, booleans, arrays, plain objects, null) cannot be serialized into the markdown body section, so they are rejected up front rather than stringified. This runs before the empty/size/character checks.","triggerScenarios":"saveMemory({body: null}) when the caller treats absent body as null, saveMemory({body: 42}) or saveMemory({body: {note: 'x'}}) from untyped input, saveMemory({body: ['line1','line2']}) assuming arrays are joined, or normalizeMemory({body: undefined}) when a destructuring step dropped the field.","commonSituations":"Calling saveMemory with a partially-built object from a form or CLI arg parser that leaves body unset. Passing through JSON.parse() output where body was missing and became undefined. Refactoring that changed body from string to {text, format} object without updating the call site.","solutions":["Always pass body as a string literal or string variable: body: String(input.body ?? '').","If body is optional in your wrapper, default it: const body = input.body == null ? '' : String(input.body);","For array input, join explicitly: body: lines.join('\\n').","Add a TypeScript type { body: string } on the input shape so the mistake surfaces at compile time."],"exampleFix":"// before\nsaveMemory({ title: 'note', body: req.json.body }); // body parsed as null/number\n\n// after\nsaveMemory({\n  title: 'note',\n  body: typeof req.json.body === 'string' ? req.json.body : ''\n});","handlingStrategy":"type-guard","validationCode":"if (typeof input.body !== 'string') {\n  throw new TypeError('input.body must be a string; got ' + typeof input.body);\n}\nsaveMemory(input);","typeGuard":"function isMemoryBody(value): value is string {\n  return typeof value === 'string';\n}","tryCatchPattern":"try {\n  saveMemory(input);\n} catch (err) {\n  if (/memory body must be a string/.test(err.message)) {\n    saveMemory({ ...input, body: String(input.body ?? '') });\n  } else throw err;\n}","preventionTips":["Type the saveMemory input as { body: string } in TypeScript.","Default at the boundary: const body = typeof input.body === 'string' ? input.body : '';","Never destructure body out of an untyped JSON.parse result without re-checking its type."],"tags":["type-check","validation","memory-vault","body"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}