affaan-m/ECC · error
must be an array.
Error message
${label} must be an array. What it means
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.
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.
Example fix
// before
normalizeMemory({ tags: 'general, tdd', ... })
// after
normalizeMemory({ tags: ['general', 'tdd'], ... }) Defensive patterns
Strategy: type-guard
Validate before calling
if (!Array.isArray(mem.tags)) mem.tags = mem.tags == null ? [] : [mem.tags];
Type guard
const isStringArray = (v) => Array.isArray(v) && v.every((x) => typeof x === 'string');
Try / catch
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; } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- memory body must be a string.
- Canonical session snapshot must be an object
- Canonical session snapshot requires
- Canonical session snapshot requires
- Canonical session snapshot requires
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/09d7bbcdd9254660.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/memory-vault-format.js:117
function validateSlug(value, label) {
const normalized = asNonEmptyString(value, label, 64);
if (!SLUG_PATTERN.test(normalized)) {
throw new Error(`${label} must be a lowercase letters/numbers slug.`);
}
return normalized;
}
function validateMemoryId(value) {
const normalized = asNonEmptyString(value, 'memory id', 132);
if (!MEMORY_ID_PATTERN.test(normalized)) {
throw new Error('memory id must match mem_<lowercase-id> and cannot contain a path.');
}
return normalized;
}
function uniqueStrings(values, { label, limit, validator }) {
if (!Array.isArray(values)) {
throw new Error(`${label} must be an array.`);
}
if (values.length > limit) {
throw new Error(`${label} has too many values (maximum ${limit}).`);
}
return values.reduce((result, value) => {
const normalized = validator(value);
if (result.includes(normalized)) {
throw new Error(`${label} must not contain duplicate values.`);
}
return [...result, normalized];
}, []);
}
function validateTimestamp(value, label) {
const normalized = asNonEmptyString(value, label, 64);
const parsed = new Date(normalized);
if (
!ISO_TIMESTAMP_PATTERN.test(normalized)View on GitHub (pinned to 8321021c54)