{"record":{"id":"7e63e380169ffe7f","repo":"thedotmack/claude-mem","slug":"syncapply-could-not-create-or-adopt-a-session-for","errorCode":null,"errorMessage":"SyncApply: could not create or adopt a session for memory_session_id=${memorySessionId}","messagePattern":"SyncApply: could not create or adopt a session for memory_session_id=(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/services/sync/SyncApply.ts","lineNumber":693,"sourceCode":"        (content_session_id, memory_session_id, project, platform_source, user_prompt, started_at, started_at_epoch, status)\n      VALUES (?, ?, ?, ?, NULL, ?, ?, 'completed')\n      ON CONFLICT(platform_source, content_session_id) DO NOTHING\n      RETURNING id\n    `).get(content, memorySessionId, project, platform, iso, createdAtEpoch) as { id: number } | null;\n\n    let sessionId: number;\n    if (inserted) {\n      logger.debug('SYNC_APPLY', 'Created stub sdk_session for remote memory session', {\n        memorySessionId,\n        project,\n      });\n      sessionId = inserted.id;\n    } else {\n      const adopted = this.db.prepare(\n        'SELECT id FROM sdk_sessions WHERE platform_source = ? AND content_session_id = ?'\n      ).get(platform, content) as { id: number } | undefined;\n      if (!adopted) {\n        throw new Error(`SyncApply: could not create or adopt a session for memory_session_id=${memorySessionId}`);\n      }\n      sessionId = adopted.id;\n    }\n\n    this.claimParkedTitle(sessionId, SyncApply.parkedTitleMemKey(memorySessionId));\n    if (contentSessionId) {\n      this.claimParkedTitle(sessionId, SyncApply.parkedTitleContentKey(platform, contentSessionId));\n    }\n    return sessionId;\n  }\n\n  private applyObservation(op: SyncOp, body: Record<string, unknown>, chromaJobs: ChromaJob[]): 'applied' | 'stale' {\n    const memorySessionId = fieldString(op, body, 'memory_session_id');\n    const project = fieldString(op, body, 'project');\n    const type = fieldString(op, body, 'type');\n    const createdAtEpoch = fieldNumber(op, body, 'created_at_epoch');\n    if (!memorySessionId || !project || !type || createdAtEpoch === null) {\n      throw invalidOp(op, 'observation body requires memory_session_id, project, type, created_at_epoch');","sourceCodeStart":675,"sourceCodeEnd":711,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d768ba364302d12b76e69e4f021f0bb1d2d50ed6/src/services/sync/SyncApply.ts#L675-L711","documentation":"Thrown in ensureSessionForMemoryId when neither creating a stub sdk_session nor adopting an existing one succeeded. The INSERT ... ON CONFLICT(platform_source, content_session_id) DO NOTHING returned nothing (a conflicting row already owns that content id), and the follow-up SELECT by (platform_source, content_session_id) found no row. This is an inconsistent state: the conflict blocked insert, yet no row matches the conflicting key.","triggerScenarios":"applyObservation/applyCanonicalRowOp resolves a memory_session_id to a local sdk_session. The INSERT is blocked by the unique (platform_source, content_session_id) constraint, then `SELECT id FROM sdk_sessions WHERE platform_source=? AND content_session_id=?` returns undefined. Should not happen if the constraint and the select key agree.","commonSituations":"Schema drift between the unique index columns and the SELECT columns (e.g. platform normalization differs between insert and select), a concurrent transaction that deleted the conflicting row between insert and select, a partial/failed migration (v33) leaving the constraint without matching rows, or a platform_source value normalized differently in the two statements.","solutions":["Verify the (platform_source, content_session_id) unique index exists and matches the SELECT predicate exactly (migration v33).","Check that the `platform` and `content` variables passed to the SELECT equal the values the INSERT used (normalization must be identical).","Look for a concurrent delete/rollback on sdk_sessions between the INSERT and SELECT; wrap the resolution in the same transaction consistently.","Run the DB integrity check / re-run pending migrations to repair schema state."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Pre-resolve the session id the same way ensureSessionForMemoryId does,\n// to surface the inconsistency before batch apply:\nfunction preresolveSession(db: Database, platform: string, content: string): number | undefined {\n  return (db.prepare('SELECT id FROM sdk_sessions WHERE platform_source=? AND content_session_id=?')\n    .get(platform, content) as { id: number } | undefined)?.id;\n}","typeGuard":null,"tryCatchPattern":"try { apply.applyOps(page, opts); }\ncatch (e) {\n  if (e instanceof Error && e.message.startsWith('SyncApply: could not create or adopt a session')) {\n    // schema/constraint drift or concurrent delete — investigate, skip op\n    logger.error('SYNC_APPLY', e.message); return;\n  }\n  throw e;\n}","preventionTips":["Run all DB migrations (esp. v33 unique index) before enabling sync apply.","Normalize platform_source identically in INSERT and SELECT paths.","Avoid concurrent deletes of sdk_sessions during a sync-apply batch."],"tags":["sync","sync-apply","database","constraint","session-resolution"],"backgroundTag":null,"analyzedSha":"d768ba364302d12b76e69e4f021f0bb1d2d50ed6","analyzedAt":"2026-08-12T23:52:55.241Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}