{"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":"validation","errorClass":"Error","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/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/memory-vault-format.js#L99-L135","documentation":"Thrown by uniqueStrings() when the values argument is not an array. uniqueStrings is the shared validator for list-valued memory fields (tags, links, targetHarnesses, etc.) and requires an actual Array instance.","triggerScenarios":"Passing a comma-separated string instead of an array, an object, undefined, or null where the schema expects a list.","commonSituations":"Deserializing frontmatter that has a scalar where a list was expected; a generator that conditionally produces a single value instead of a list.","solutions":["Wrap the value in an array before passing it (Array.isArray check, or Array.from / [].concat).","Fix the upstream producer so the field is always a list.","If the field is optional, pass an empty array rather than null."],"exampleFix":"// before\nuniqueStrings('tag-a,tag-b', { label: 'tags', limit: 32, validator: v => v });\n// after\nuniqueStrings(['tag-a', 'tag-b'], { label: 'tags', limit: 32, validator: v => v });","handlingStrategy":"type-guard","validationCode":"function asStringArray(value) {\n  return Array.isArray(value) ? value : (value == null ? [] : [value]);\n}\n// before calling uniqueStrings:\nconst tags = asStringArray(raw.tags);","typeGuard":"function isStringArray(value) {\n  return Array.isArray(value) && value.every(v => typeof v === 'string');\n}","tryCatchPattern":"try {\n  result = uniqueStrings(values, opts);\n} catch (e) {\n  if (/must be an array/.test(e.message)) result = uniqueStrings(values == null ? [] : [values], opts);\n  else throw e;\n}","preventionTips":["Coerce scalar values to single-element arrays at the deserialization boundary.","Use JSON schema 'type: array' for list fields.","Default optional list fields to [] rather than null."],"tags":["memory-vault","validation","array","format"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}