mastra-ai/mastra · error
Could not save the active model pack
Error message
Could not save the active model pack
What it means
When switching the model for a mode, the TUI first persists the new model pack id to thread settings, then reads it back to verify the write actually landed. If the round-trip read does not equal the pack id that was just written, switchCurrentModeModel throws 'Could not save the active model pack'. This is a write-verification failure indicating the settings backend silently dropped or failed to persist the value.
Source
Thrown at mastracode/tui/src/tui/commands/models.ts:93
});
}
nextSettings.models.activeModelPackId = nextPackId;
nextSettings.models.modeDefaults = modeModels;
}
let modeSettingSaved = false;
let packSettingSaved = false;
let globalSettingsWriteStarted = false;
try {
await ctx.state.session.thread.setSetting({ key: modeSettingKey, value: modelId });
modeSettingSaved = true;
const savedModeSetting = await ctx.state.session.thread.getSetting({ key: modeSettingKey });
if (savedModeSetting !== modelId) throw new Error(`Could not save the ${modeId} mode model`);
await ctx.state.session.thread.setSetting({ key: THREAD_ACTIVE_MODEL_PACK_ID_KEY, value: nextPackId });
packSettingSaved = true;
const savedPackSetting = await ctx.state.session.thread.getSetting({ key: THREAD_ACTIVE_MODEL_PACK_ID_KEY });
if (savedPackSetting !== nextPackId) throw new Error('Could not save the active model pack');
globalSettingsWriteStarted = true;
saveSettings(nextSettings);
await ctx.state.session.model.switch({ modelId, scope: 'global' });
} catch (error) {
if (globalSettingsWriteStarted) {
try {
saveSettings(settings);
} catch {
// Keep the original failure. The thread and active model still roll back below.
}
}
const rollbacks: Array<Promise<unknown>> = [];
if (packSettingSaved) {
rollbacks.push(
ctx.state.session.thread.setSetting({
key: THREAD_ACTIVE_MODEL_PACK_ID_KEY,
value: previousPackSetting,View on GitHub (pinned to 75dd419e61)
Solutions
- Check that the thread's storage/settings backend persists values synchronously and that getSetting reflects a prior setSetting
- Retry the model switch; transient races with another writer resolve on a second attempt
- Verify no other TUI session or process is concurrently writing THREAD_ACTIVE_MODEL_PACK_ID_KEY for the same thread
- Inspect the thread settings implementation for swallowed errors in setSetting
- Clear/recreate the thread state if its settings record is corrupted
Example fix
// before (custom storage adapter silently ignoring writes)
async setSetting({ key, value }) { this.pending[key] = value; }
// after
async setSetting({ key, value }) {
this.pending[key] = value;
await this.persist();
const check = await this.getSetting({ key });
if (check !== value) throw new Error(`Failed to persist setting ${key}`);
} Defensive patterns
Strategy: try-catch
Validate before calling
const stored = await ctx.state.session.thread.getSetting({ key: THREAD_ACTIVE_MODEL_PACK_ID_KEY });
if (stored !== undefined && typeof stored !== 'string') throw new Error('Thread settings backend returned unexpected value'); Type guard
function isPersistedSetting(v: unknown): v is string { return typeof v === 'string'; } Try / catch
try {
await switchCurrentModeModel(ctx, modeId, modelId, packId);
} catch (error) {
if (error instanceof Error && error.message.includes('Could not save')) {
// surface a retry / settings-backend diagnostics UI
}
} Prevention
- Use a storage adapter whose setSetting is durable and immediately readable
- Avoid two TUI sessions writing settings for the same thread concurrently
- Add a health check that round-trips a dummy setting at startup
- Log the settings backend type alongside this error for diagnosis
When it happens
Trigger: Calling the mode-model switch command when thread.setSetting({ key: THREAD_ACTIVE_MODEL_PACK_ID_KEY, ... }) succeeds without throwing but the subsequent getSetting returns a different value or undefined — e.g. the thread storage adapter silently swallows writes, the thread was closed/recreated mid-switch, or a concurrent write overwrote the key between set and get.
Common situations: Storage backend misconfiguration (in-memory or ephemeral store that doesn't persist), corrupted thread state, race with another TUI session writing settings for the same thread, or a custom Thread/Settings implementation whose setSetting doesn't immediately reflect in getSetting.
Related errors
- Could not save the ${modeId} mode model
- Storage is not configured
- AcpAgent does not support resuming suspended generate calls
- AcpAgent does not support resuming suspended stream calls
- ACP prompt stopped before completing: ${response.stopReason}
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/f386f0eb26b7a798.
Report an issue: GitHub.