{"record":{"id":"20a151bc96869293","repo":"affaan-m/ECC","slug":"memory-memory-id-already-exists-writes-are-cre","errorCode":null,"errorMessage":"Memory ${memory.id} already exists; writes are create-only.","messagePattern":"Memory (.+?) already exists; writes are create-only\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/memory-vault.js","lineNumber":339,"sourceCode":"  const memory = normalizeSaveInput(input || {}, options);\n  const secretKinds = findPotentialSecrets(JSON.stringify(memory));\n  if (secretKinds.length > 0) {\n    throw new Error(`Refusing to save memory containing a suspected secret (${secretKinds.join(', ')}).`);\n  }\n\n  const root = assertMemoryRootSafe(roots, memory.scope);\n  fs.mkdirSync(root, { recursive: true, mode: 0o700 });\n  ensureProjectScopeIgnored(roots, memory.scope);\n  const directory = path.join(root, `${memory.kind}s`);\n  assertMemoryDirectorySafe(directory, root);\n  fs.mkdirSync(directory, { recursive: true, mode: 0o700 });\n  const destination = path.join(directory, `${memory.id}.md`);\n\n  try {\n    writeCreateOnlyTextFile(destination, serializeMemoryDocument(memory), root);\n  } catch (error) {\n    if (error && error.code === 'EEXIST') {\n      throw new Error(`Memory ${memory.id} already exists; writes are create-only.`);\n    }\n    throw error;\n  }\n  return { memory, path: destination };\n}\n\nfunction walkMemoryRoot(root, maxEntries = MAX_FILES) {\n  if (!root || !fs.existsSync(root)) {\n    return {\n      paths: [],\n      skippedSymlinks: [],\n      skippedSymlinkCount: 0,\n      truncated: false,\n      visitedCount: 0,\n    };\n  }\n\n  const paths = [];","sourceCodeStart":321,"sourceCodeEnd":357,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/memory-vault.js#L321-L357","documentation":"Vault writes are create-only: writeCreateOnlyTextFile opens the destination with O_CREAT|O_EXCL, so it fails with EEXIST if the file is already present. saveMemory translates that EEXIST into an explicit 'writes are create-only' error, refusing to overwrite an existing memory. This makes memory IDs immutable-once-written and prevents accidental clobbering of audit history.","triggerScenarios":"Calling saveMemory with an input.id (or a generated id from a custom idFactory) that already names a file on disk under <root>/<kind>s/<id>.md. Also possible after a retry that did not change the id, or when an idFactory produces collisions.","commonSituations":"Retrying a failed save without regenerating the id; passing a deterministic id that already exists; an idFactory based on a hash of content colliding; a partial prior write that left the file in place; manually crafting an id that conflicts.","solutions":["Omit input.id so the vault generates a fresh unique id (defaultMemoryId uses date + random UUID suffix).","If you must use a stable id and the existing memory is wrong, delete the old file first (rm <root>/<kind>s/<id>.md) and re-save — but treat this as editing history, not updating in place.","If using a custom idFactory, ensure it cannot return an id already present on disk (check fs.existsSync or use crypto.randomUUID).","For 'upsert' semantics, read the existing memory, then save a new memory with a new id and a link to the old one, rather than trying to overwrite."],"exampleFix":"// before\nsaveMemory({ id: 'mem_notes', title: 'x', body: '...' }); // second call fails\n// after: let the vault mint a unique id\nsaveMemory({ title: 'x', body: '...' }); // id auto-generated as mem_YYYYMMDD_<random>","handlingStrategy":"validation","validationCode":"const fs = require('fs');\nconst path = require('path');\nfunction memoryIdIsFree(roots, scope, kind, id) {\n  const dest = path.join(roots[scope], `${kind}s`, `${id}.md`);\n  return !fs.existsSync(dest);\n}\n// before saveMemory with an explicit id:\nif (!memoryIdIsFree(roots, scope, kind, input.id)) {\n  throw new Error(`Memory ${input.id} already exists; writes are create-only.`);\n}","typeGuard":null,"tryCatchPattern":"try { saveMemory(input); }\ncatch (error) {\n  if (/writes are create-only/.test(error.message)) {\n    // generate a fresh id and retry\n    return saveMemory({ ...input, id: undefined });\n  }\n  throw error;\n}","preventionTips":["Omit input.id whenever possible so the vault mints a unique id.","If using a custom idFactory, base it on crypto.randomUUID to avoid collisions.","For 'update' semantics, save a new memory with a link to the old one rather than overwriting.","Before re-saving after an error, regenerate the id."],"tags":["memory-vault","validation","idempotency","filesystem"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}