affaan-m/ECC · error

memory id must match mem_<lowercase-id> and cannot contain…

Error message

memory id must match mem_<lowercase-id> and cannot contain a path.

What it means

validateMemoryId checks that a memory id is a string of at most 132 characters matching /^mem_[a-z0-9][a-z0-9_-]{2,127}$/ — it must start with the literal 'mem_' followed by at least 3 lowercase characters. The error message also signals path-traversal protection: ids containing '/', '..', or backslashes are rejected so an id can never escape the vault directory.

Solutions

  1. Prefix the id with 'mem_' and lowercase all characters, e.g. mem_ + crypto.randomUUID().toLowerCase().
  2. Verify at least 3 characters follow the prefix and only [a-z0-9_-] are used (no dots, slashes, or spaces).
  3. Strip any path segments ('/', '..') from the value before formatting.
  4. Keep the total length at or below 132 characters.

Example fix

// before
const id = crypto.randomUUID(); // '3f8a...' -> rejected
// after
const id = 'mem_' + crypto.randomUUID().toLowerCase().replace(/-/g, '');
Defensive patterns

Strategy: validation

Validate before calling

function isValidMemoryId(v) { return typeof v === 'string' && /^mem_[a-z0-9][a-z0-9_-]{2,127}$/.test(v) && v.length <= 132; }
if (!isValidMemoryId(id)) id = 'mem_' + String(id).toLowerCase().replace(/[^a-z0-9_-]/g, '').slice(0, 127);

Type guard

const isMemoryId = (v) => typeof v === 'string' && /^mem_[a-z0-9][a-z0-9_-]{2,127}$/.test(v);

Try / catch

try { normalizeMemory(mem); } catch (e) { if (e.message.includes('must match mem_')) { mem.id = toMemoryId(mem.id); } else throw e; }

Prevention

When it happens

Trigger: Calling normalizeMemory or the memoryId helper with an id like 'abc123' (missing mem_ prefix), 'MEM_abc' (uppercase), 'mem_a' (too short, needs 3+ chars after prefix), 'mem_../../secret', or a non-string value.

Common situations: Generating ids with crypto.randomUUID() (contains hyphens are OK but lacks mem_ prefix); using uppercase UUIDs; constructing ids by concatenating user paths; legacy records stored with the old id format before the mem_ convention was adopted.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/abdee46c569e1828. Report an issue: GitHub.

Appendix: source

Thrown at scripts/lib/memory-vault-format.js:110

  const normalized = asNonEmptyString(value, label, 64);
  if (!allowed.includes(normalized)) {
    throw new Error(`${label} must be one of: ${allowed.join(', ')}.`);
  }
  return normalized;
}

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];
  }, []);

View on GitHub (pinned to 8321021c54)