thedotmack/claude-mem · error

SyncApply: could not create or adopt a session for memory_se

Error message

SyncApply: could not create or adopt a session for memory_session_id=${memorySessionId}

What it means

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.

Source

Thrown at src/services/sync/SyncApply.ts:693

        (content_session_id, memory_session_id, project, platform_source, user_prompt, started_at, started_at_epoch, status)
      VALUES (?, ?, ?, ?, NULL, ?, ?, 'completed')
      ON CONFLICT(platform_source, content_session_id) DO NOTHING
      RETURNING id
    `).get(content, memorySessionId, project, platform, iso, createdAtEpoch) as { id: number } | null;

    let sessionId: number;
    if (inserted) {
      logger.debug('SYNC_APPLY', 'Created stub sdk_session for remote memory session', {
        memorySessionId,
        project,
      });
      sessionId = inserted.id;
    } else {
      const adopted = this.db.prepare(
        'SELECT id FROM sdk_sessions WHERE platform_source = ? AND content_session_id = ?'
      ).get(platform, content) as { id: number } | undefined;
      if (!adopted) {
        throw new Error(`SyncApply: could not create or adopt a session for memory_session_id=${memorySessionId}`);
      }
      sessionId = adopted.id;
    }

    this.claimParkedTitle(sessionId, SyncApply.parkedTitleMemKey(memorySessionId));
    if (contentSessionId) {
      this.claimParkedTitle(sessionId, SyncApply.parkedTitleContentKey(platform, contentSessionId));
    }
    return sessionId;
  }

  private applyObservation(op: SyncOp, body: Record<string, unknown>, chromaJobs: ChromaJob[]): 'applied' | 'stale' {
    const memorySessionId = fieldString(op, body, 'memory_session_id');
    const project = fieldString(op, body, 'project');
    const type = fieldString(op, body, 'type');
    const createdAtEpoch = fieldNumber(op, body, 'created_at_epoch');
    if (!memorySessionId || !project || !type || createdAtEpoch === null) {
      throw invalidOp(op, 'observation body requires memory_session_id, project, type, created_at_epoch');

View on GitHub (pinned to d768ba3643)

Solutions

  1. Verify the (platform_source, content_session_id) unique index exists and matches the SELECT predicate exactly (migration v33).
  2. Check that the `platform` and `content` variables passed to the SELECT equal the values the INSERT used (normalization must be identical).
  3. Look for a concurrent delete/rollback on sdk_sessions between the INSERT and SELECT; wrap the resolution in the same transaction consistently.
  4. Run the DB integrity check / re-run pending migrations to repair schema state.
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-resolve the session id the same way ensureSessionForMemoryId does,
// to surface the inconsistency before batch apply:
function preresolveSession(db: Database, platform: string, content: string): number | undefined {
  return (db.prepare('SELECT id FROM sdk_sessions WHERE platform_source=? AND content_session_id=?')
    .get(platform, content) as { id: number } | undefined)?.id;
}

Try / catch

try { apply.applyOps(page, opts); }
catch (e) {
  if (e instanceof Error && e.message.startsWith('SyncApply: could not create or adopt a session')) {
    // schema/constraint drift or concurrent delete — investigate, skip op
    logger.error('SYNC_APPLY', e.message); return;
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12). Data as JSON: /api/errors/7e63e380169ffe7f. Report an issue: GitHub.