Yeachan-Heo/oh-my-codex · warning · CommittedLaunchBlockedError

Session pointer committed, but lock release left recovery ev

Error message

Session pointer committed, but lock release left recovery evidence.

What it means

After a successful primary operation, the finalizer releases the pointer lock; if releasePointerLock returns failures, releaseFailureError(releaseFailures) is thrown with this message — the session pointer WAS committed, but the lock could not be fully released, leaving recovery evidence behind. The underlying release failures are included for diagnosis. Unlike error 1346, the data change succeeded; only cleanup failed.

Source

Thrown at src/hooks/session.ts:3775

      ...(historyEntry.active_session_id ? { active_session_id: historyEntry.active_session_id } : {}),
      ...(historyEntry.preserved_active_session_id ? { preserved_active_session_id: historyEntry.preserved_active_session_id } : {}),
      timestamp: endTime,
    }).catch(() => {});
    traceSessionFinalizationOperation('session-end-log-done');
  } catch (error) {
    primary = error;
  }

  traceSessionFinalizationOperation('lock-release-start');
  const releaseFailures = await releasePointerLock(lock);
  traceSessionFinalizationOperation('lock-release-done');
  if (primary) {
    if (isSessionPointerLaunchAbort(primary) && releaseFailures.length > 0) {
      throw recoveryAbort(context, primary as ResolvedSessionPointerAbort, releaseFailures, 'lock-release');
    }
    throw primary;
  }
  if (releaseFailures.length > 0) throw releaseFailureError(releaseFailures);
  emitDegradedDurabilityWarning('session pointer end', tracker);
  return revalidation;
}

/** Reset session-scoped HUD/metrics files at launch. */
export async function resetSessionMetrics(cwd: string, sessionId?: string): Promise<void> {
  const context = resolveSessionPointerContext(cwd);
  const omxDir = omxRoot(context.cwd);
  await nodeMkdir(omxDir, { recursive: true });
  await transactionDependencies.fs.mkdir(context.baseStateDir, { recursive: true });

  const now = new Date().toISOString();
  await nodeWriteFile(join(omxDir, 'metrics.json'), JSON.stringify({
    total_turns: 0,
    session_turns: 0,
    last_activity: now,
    session_input_tokens: 0,
    session_output_tokens: 0,

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Treat the session data as committed; run the explicit recovery/cleanup routine to remove leftover lock evidence
  2. Inspect the lockPath directory and remove stale lock artifacts manually if recovery tooling is unavailable
  3. Fix directory permissions so lock files can be unlinked
  4. Add post-run hygiene (or a scheduled recovery pass) that clears stale locks before new sessions start
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-clean stale lock artifacts before starting a session
await clearStalePointerLocks(lockPathDir, /* olderThan */ ms('1h'));

Type guard

function isReleaseFailure(e: unknown): boolean {
  return typeof (e as { message?: string })?.message === 'string' &&
    (e as { message: string }).message.includes('lock release left recovery evidence');
}

Try / catch

catch (e) {
  if (isReleaseFailure(e)) {
    // data committed; schedule recovery cleanup and continue (warning, not fatal)
    scheduleRecoveryCleanup(context);
  } else throw e;
}

Prevention

When it happens

Trigger: releasePointerLock failing to delete lock artifacts (stale lock file, rmdir/unlink errors) after the pointer transaction committed successfully — releaseFailures.length > 0 with no primary abort.

Common situations: Leftover lock files from prior crashed runs blocking cleanup removal; restrictive permissions on the lock directory; filesystems with delayed directory entry visibility (NFS, some CI runners); external processes recreating/holding lock files.

Related errors


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/932d5084fd1532f9. Report an issue: GitHub.