thedotmack/claude-mem · error
No mode loaded. Call loadMode() first.
Error message
No mode loaded. Call loadMode() first.
What it means
getActiveMode() returns the currently merged ModeConfig, but the manager is a stateful object that requires loadMode() to have been called first. If activeMode is still unset, it throws this error. It is a lifecycle/initialization-order guard, not a data problem.
Solutions
- Call `await modeManager.loadMode(...)` before any getActiveMode()/getObservationTypes() call.
- Check why the earlier loadMode() failed (fix that error first) — active mode stays unset.
- Guard call sites: only query the manager after initialization completes (e.g. an `initialized` flag/promise).
- If modes are optional in your context, wrap access in try-catch and use a default config.
Example fix
// before
const mm = new ModeManager(dirs);
const types = mm.getObservationTypes(); // throws
// after
const mm = new ModeManager(dirs);
await mm.loadMode('code');
const types = mm.getObservationTypes(); Defensive patterns
Strategy: try-catch
Validate before calling
let managerReady = false;
async function initManager(m, modeId) { await m.loadMode(modeId); managerReady = true; }
if (!managerReady) throw new Error('ModeManager not initialized'); Type guard
const isReady = (m: ModeManager & { activeMode?: unknown }): boolean => (m as any).activeMode != null; Try / catch
try { const types = manager.getObservationTypes(); } catch (e) { if (e.message.includes('No mode loaded')) { await manager.loadMode('code'); return manager.getObservationTypes(); } throw e; } Prevention
- Make loadMode part of an explicit init() and gate all accessors on it.
- Await manager initialization before reading observation types.
- Do not swallow loadMode rejections — a swallowed failure leads to this error later.
- In tests, always load a mode in beforeEach before touching accessors.
When it happens
Trigger: Calling getActiveMode() (directly or via getObservationTypes()) on a fresh ModeManager instance before any successful loadMode() call, or after loadMode() threw and left no active mode.
Common situations: Constructor-time code reading observation types before mode load completes; async initialization race where getObservationTypes() runs before await loadMode() resolves; swallowing the loadMode error earlier and continuing.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- chroma-mcp connection cancelled during shutdown
- cloud sync must be configured before queueDelete
- Corpus " " has no session — call prime first
- Critical: code.json mode file missing
- illegal observation generation job transition from
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/433abc4ad9256003.
Report an issue: GitHub.
Appendix: source
Thrown at src/services/domain/ModeManager.ts:178
}
const mergedMode = this.deepMerge(parentMode, overrideConfig);
this.activeMode = mergedMode;
this.activeModeId = modeId;
logger.debug('SYSTEM', `Loaded mode with inheritance: ${mergedMode.name} (${modeId} = ${parentId} + ${overrideId})`, undefined, {
parent: parentId,
override: overrideId,
types: mergedMode.observation_types.map(t => t.id),
concepts: mergedMode.observation_concepts.map(c => c.id)
});
return mergedMode;
}
getActiveMode(): ModeConfig {
if (!this.activeMode) {
throw new Error('No mode loaded. Call loadMode() first.');
}
return this.activeMode;
}
getActiveModeId(): string {
if (!this.activeModeId) {
throw new Error('No mode loaded. Call loadMode() first.');
}
return this.activeModeId;
}
getObservationTypes(): ObservationType[] {
return this.getActiveMode().observation_types;
}
getTypeIcon(typeId: string): string {
const type = this.getObservationTypes().find(t => t.id === typeId);
return type?.emoji || '📝';View on GitHub (pinned to d8bc9755e7)