{"record":{"id":"09d7bbcdd9254660","repo":"affaan-m/ECC","slug":"label-must-be-an-array","errorCode":null,"errorMessage":"${label} must be an array.","messagePattern":"(.+?) must be an array\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/memory-vault-format.js","lineNumber":117,"sourceCode":"function validateSlug(value, label) {\n  const normalized = asNonEmptyString(value, label, 64);\n  if (!SLUG_PATTERN.test(normalized)) {\n    throw new Error(`${label} must be a lowercase letters/numbers slug.`);\n  }\n  return normalized;\n}\n\nfunction validateMemoryId(value) {\n  const normalized = asNonEmptyString(value, 'memory id', 132);\n  if (!MEMORY_ID_PATTERN.test(normalized)) {\n    throw new Error('memory id must match mem_<lowercase-id> and cannot contain a path.');\n  }\n  return normalized;\n}\n\nfunction uniqueStrings(values, { label, limit, validator }) {\n  if (!Array.isArray(values)) {\n    throw new Error(`${label} must be an array.`);\n  }\n  if (values.length > limit) {\n    throw new Error(`${label} has too many values (maximum ${limit}).`);\n  }\n  return values.reduce((result, value) => {\n    const normalized = validator(value);\n    if (result.includes(normalized)) {\n      throw new Error(`${label} must not contain duplicate values.`);\n    }\n    return [...result, normalized];\n  }, []);\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)","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/memory-vault-format.js#L99-L135","documentation":"uniqueStrings requires its first argument to be a JavaScript Array; the library throws this error when a list field (tags, links, target harnesses, scopes) is passed as any other type. It guarantees downstream reduce() iteration is safe and every list field in a memory document has a consistent array shape.","triggerScenarios":"Passing a non-array to targetHarnesses, normalizeMemory list fields, normalizeScopes, or the kinds helper — e.g. a comma-separated string 'a,b', a Set, null, undefined, or an object mapping names to values.","commonSituations":"Frontmatter YAML parsed with a scalar instead of a list (tags: general instead of tags: [general]); JSON configs where a single item was given without array brackets; deserialization frameworks returning Set or Map instead of Array; a field omitted and defaulted to null.","solutions":["Wrap the single value in an array: 'claude-code' -> ['claude-code'].","Split comma-separated strings explicitly before passing: value.split(',').map(s => s.trim()).","Ensure the field is present and defaults to [] rather than null/undefined.","Convert Set/Map iterables with Array.from(value) if the source is an iterable."],"exampleFix":"// before\nnormalizeMemory({ tags: 'general, tdd', ... })\n// after\nnormalizeMemory({ tags: ['general', 'tdd'], ... })","handlingStrategy":"type-guard","validationCode":"if (!Array.isArray(mem.tags)) mem.tags = mem.tags == null ? [] : [mem.tags];","typeGuard":"const isStringArray = (v) => Array.isArray(v) && v.every((x) => typeof x === 'string');","tryCatchPattern":"try { normalizeMemory(mem); } catch (e) { if (e.message.includes('must be an array')) { throw new Error('Field must be a list in frontmatter, e.g. tags: [a, b]'); } throw e; }","preventionTips":["Default list fields to [] instead of null","In YAML frontmatter always use bracket or dash list syntax","Coerce single scalars to [value] before validating","Convert Set/Map results with Array.from"],"tags":["validation","type-mismatch","array","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"}