{"record":{"id":"28df09f8b9de2ecc","repo":"affaan-m/ECC","slug":"could-not-allocate-a-snapshot-filename-for-session","errorCode":null,"errorMessage":"Could not allocate a snapshot filename for session ${session.sessionId}","messagePattern":"Could not allocate a snapshot filename for session (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/loop-status.js","lineNumber":674,"sourceCode":"  }\n}\n\nfunction getSnapshotPath(outputDir, session, usedNames) {\n  const baseName = sanitizeSnapshotName(session.sessionId);\n  const hashSuffix = hashString(session.transcriptPath || session.sessionId).slice(0, 8);\n  let attempt = 0;\n\n  while (attempt < 1000) {\n    const suffix = attempt === 0 ? '' : `-${hashSuffix}${attempt === 1 ? '' : `-${attempt}`}`;\n    const fileName = `${baseName}${suffix}.json`;\n    if (!usedNames.has(fileName)) {\n      usedNames.add(fileName);\n      return path.join(outputDir, fileName);\n    }\n    attempt += 1;\n  }\n\n  throw new Error(`Could not allocate a snapshot filename for session ${session.sessionId}`);\n}\n\nfunction writeStatusSnapshots(payload, writeDir) {\n  if (!writeDir) {\n    return null;\n  }\n\n  const outputDir = path.resolve(writeDir);\n  fs.mkdirSync(outputDir, { recursive: true });\n\n  const usedNames = new Set(['index.json']);\n  const sessions = payload.sessions.map(session => {\n    const snapshotPath = getSnapshotPath(outputDir, session, usedNames);\n    atomicWriteJson(snapshotPath, {\n      generatedAt: payload.generatedAt,\n      schemaVersion: 'ecc.loop-status.session.v1',\n      session,\n    });","sourceCodeStart":656,"sourceCodeEnd":692,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/loop-status.js#L656-L692","documentation":"When writing per-session snapshot files, the allocator tries to build a unique filename from the session id, retrying with an incremented attempt counter if the name collides. If it exhausts its attempts without finding a free, valid name it throws 'Could not allocate a snapshot filename for session <sessionId>'. This is a defensive invariant: in practice it indicates pathological session ids or a saturated output directory naming scheme.","triggerScenarios":"Calling writeStatusSnapshots with --write-dir where a session id produces a filename that cannot be made unique after all retry attempts (e.g. extremely long session ids colliding after truncation, or a hostile/odd sessionId string).","commonSituations":"Session ids containing path-unsafe or extremely long characters from a third-party tool, or thousands of snapshots in one directory hitting naming limits.","solutions":["Inspect the reported sessionId for unusual characters or extreme length and sanitize/shorten it at the source.","Point --write-dir at a fresh directory to reduce name collisions from existing snapshots.","Update the script to increase the attempt limit or include a hash/random suffix in the filename.","Retry the run; a transient collision with concurrently written snapshots may resolve on the next attempt."],"exampleFix":"// before\nnode scripts/loop-status.js --write-dir ./snapshots   # pathological sessionId\n// after\nrm -rf ./snapshots && node scripts/loop-status.js --write-dir ./snapshots  # or patch allocator to append a random suffix","handlingStrategy":"try-catch","validationCode":"if (!/^[-\\w.]{1,64}$/.test(session.sessionId)) sanitize or reject the session id before snapshotting;","typeGuard":"const isSafeSessionId = (id) => typeof id === 'string' && id.length > 0 && id.length <= 128 && !id.includes('/');","tryCatchPattern":"try { writeStatusSnapshots(payload, dir); } catch (e) { if (e.message.startsWith('Could not allocate a snapshot filename')) { console.error('Snapshot naming failed; clean the output dir or shorten the session id'); } else throw e; }","preventionTips":["Use fresh output directories per run","Sanitize session ids from third-party tools","Patch the allocator to add a random/hash suffix instead of failing"],"tags":["filesystem","naming-collision","internal-error"],"backgroundTag":"internal-invariant-violation","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}