{"record":{"id":"f00481667a98324f","repo":"nexu-io/open-design","slug":"invalid-memory-id","errorCode":null,"errorMessage":"invalid memory id","messagePattern":"invalid memory id","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/daemon/src/memory.ts","lineNumber":153,"sourceCode":"    .slice(0, 48);\n  if (cleaned.length > 0) return `${safeType}_${cleaned}`;\n  // FNV-1a 32-bit on the original name. Tiny, deterministic, no\n  // dependencies. Collisions are still possible, but for the dozens of\n  // memories a user is likely to accumulate, the birthday risk is\n  // negligible.\n  let h = 0x811c9dc5 >>> 0;\n  for (let i = 0; i < raw.length; i++) {\n    h = (h ^ raw.charCodeAt(i)) >>> 0;\n    h = Math.imul(h, 0x01000193) >>> 0;\n  }\n  return `${safeType}_n${h.toString(36)}`;\n}\n\nfunction entryPath(dataDir, id) {\n  // Defence in depth: the id arrives from the network. Reject anything\n  // that could escape the memory dir or break the .md convention.\n  if (typeof id !== 'string' || !/^[a-z0-9_]+$/.test(id) || id.length > 96) {\n    throw new Error('invalid memory id');\n  }\n  return path.join(memoryDir(dataDir), `${id}.md`);\n}\n\nfunction indexPath(dataDir) {\n  return path.join(memoryDir(dataDir), INDEX_FILE);\n}\n\nfunction configPath(dataDir) {\n  return path.join(memoryDir(dataDir), CONFIG_FILE);\n}\n\n// Whitelist of fields the extraction override may contain. Anything else\n// in the patch is dropped to keep `.config.json` from accumulating\n// arbitrary user-supplied keys (e.g. a typo'd field that quietly breaks\n// the extractor on the next restart).\nconst VALID_EXTRACTION_PROVIDERS = new Set([\n  'anthropic',","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/memory.ts#L135-L171","documentation":"A memory id failed validation in entryPath(). The id must be a string matching /^[a-z0-9_]+$/, and must not exceed 96 characters. This is a defence-in-depth check because ids arrive from network requests and are used directly in filesystem path construction (path.join with the id + '.md').","triggerScenarios":"API caller sends an id with uppercase letters, hyphens, dots, slashes, spaces, or special characters; id exceeds 96 chars; id is null, undefined, or not a string; path traversal attempt with '../' sequences.","commonSituations":"External system generates UUIDs with hyphens (e.g. 'a1b2c3d4-e5f6'); user-supplied id with invalid characters; camelCase id like 'myMemory'; malicious path traversal attempt.","solutions":["Use only lowercase alphanumeric and underscore characters in memory ids","Keep ids at or under 96 characters","Use deriveMemoryId(type, name) to generate safe ids automatically from type and name","Sanitize external ids by lowercasing and replacing non-alphanumeric characters with underscores before passing to memory APIs"],"exampleFix":"// before — UUID with hyphens fails validation\nupdateMemoryTreeNode(dataDir, 'a1b2c3d4-e5f6-7890', patch);\n\n// after — sanitize to valid slug\nconst safeId = 'a1b2c3d4-e5f6-7890'.toLowerCase().replace(/[^a-z0-9]+/g, '_');\nupdateMemoryTreeNode(dataDir, safeId, patch);","handlingStrategy":"validation","validationCode":"const MEMORY_ID_RE = /^[a-z0-9_]+$/;\nconst MEMORY_ID_MAX_LEN = 96;\n\nfunction assertValidMemoryId(id) {\n  if (typeof id !== 'string' || !MEMORY_ID_RE.test(id) || id.length > MEMORY_ID_MAX_LEN) {\n    throw new Error(`Invalid memory id: ${JSON.stringify(id)}. Must match ${MEMORY_ID_RE} and be <= ${MEMORY_ID_MAX_LEN} chars.`);\n  }\n}","typeGuard":"function isValidMemoryId(id: unknown): id is string {\n  return typeof id === 'string' && /^[a-z0-9_]+$/.test(id) && id.length <= 96;\n}","tryCatchPattern":null,"preventionTips":["Use deriveMemoryId(type, name) to generate safe ids — it handles slugification and hashing automatically","Sanitize external ids (UUIDs, camelCase) by lowercasing and replacing non-alphanumerics with underscores before passing to memory APIs","Never pass raw user input or external identifiers directly as memory ids without validation","Treat this check as a security boundary — it prevents path traversal through the memory directory"],"tags":["memory","validation","security","path-traversal"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}