laurent22/joplin · error · Error
The active profile cannot be deleted. Switch to a different
Error message
The active profile cannot be deleted. Switch to a different profile and try again.
What it means
Thrown by `deleteProfile` in the mobile profile switcher when the profile being deleted (`options.toDelete.id`) equals the currently active profile id (`options.profileConfig.currentProfileId`). Deleting the active profile would leave the app with no current profile, so the operation is blocked before any filesystem or database work begins.
Source
Thrown at packages/app-mobile/components/ProfileSwitcher/utils/deleteProfile.ts:21
import { deleteProfileById, getCurrentProfile, isSubProfile } from '@joplin/lib/services/profileConfig';
import Setting from '@joplin/lib/models/Setting';
import shim, { MessageBoxType } from '@joplin/lib/shim';
import Logger from '@joplin/utils/Logger';
import resolvePathWithinDir from '@joplin/lib/utils/resolvePathWithinDir';
import DatabaseDriver from '@joplin/lib/database-driver';
import { _ } from '@joplin/lib/locale';
const logger = Logger.create('deleteProfile');
interface DeleteProfileOptions {
toDelete: Profile;
profileConfig: ProfileConfig;
databaseDriver: DatabaseDriver;
}
const deleteProfile = async (options: DeleteProfileOptions) => {
logger.info('Deleting profile config', options.toDelete.id);
if (options.toDelete.id === options.profileConfig.currentProfileId) throw new Error(_('The active profile cannot be deleted. Switch to a different profile and try again.'));
const subProfile = isSubProfile(options.toDelete);
// Deleting the default profile must be handled differently. We can't delete the whole directory because it contains other profiles and global settings
if (subProfile) {
const newConfig = deleteProfileById(options.profileConfig, options.toDelete.id);
// Save the profile config early. If the later deletion steps fail, this prevents the user from
// opening a partially-deleted profile. The default profile does not get deleted from the list,
// but the data will be cleared
await saveProfileConfig(newConfig);
}
// Retrieve and validate both the database name and resources directory
// **before** doing any deletion.
const databaseName = getTargetDatabaseName(options);
const resourcesDir = getTargetResourceDirectory(options);
const pluginDataDir = getTargetPluginDataDirectory(options);
logger.info('Deleting database', databaseName);View on GitHub (pinned to 2654b33620)
Solutions
- Switch to a different profile first (`switchProfile`), then delete the inactive one.
- In the UI, disable the delete control for the row whose id equals `currentProfileId`.
- Pre-check before invoking: `if (toDelete.id === profileConfig.currentProfileId) { /* warn user */ return; }`.
- Reload `profileConfig` immediately before the delete call to avoid a stale snapshot.
Example fix
// before
deleteProfile({ toDelete, profileConfig, databaseDriver });
// after
if (toDelete.id === profileConfig.currentProfileId) {
await showDialog(_('Switch to a different profile before deleting this one.'));
return;
}
await deleteProfile({ toDelete, profileConfig, databaseDriver }); Defensive patterns
Strategy: validation
Validate before calling
const isActive = (toDelete, profileConfig) =>
toDelete.id === profileConfig.currentProfileId;
if (isActive(toDelete, profileConfig)) {
await showDialog(_('Switch to a different profile before deleting this one.'));
return;
}
await deleteProfile({ toDelete, profileConfig, databaseDriver }); Type guard
null
Try / catch
try {
await deleteProfile({ toDelete, profileConfig, databaseDriver });
} catch (error) {
if (/active profile cannot be deleted/i.test(error.message)) {
await showSwitchProfilePrompt();
return;
}
throw error;
} Prevention
- Disable the delete control in the UI for the active profile row.
- Reload profileConfig immediately before deleting to avoid stale snapshots.
- Switch profiles programmatically before deleting the previously-active one.
When it happens
Trigger: Calling `deleteProfile({ toDelete, profileConfig, databaseDriver })` where `toDelete.id === profileConfig.currentProfileId`. Reached from the profile switcher UI when the user taps delete on the profile the app is currently running under.
Common situations: Single-profile installs where the user tries to delete the only/active profile; UI bug that does not disable the delete button for the active row; stale `profileConfig` snapshot read before a profile switch completed.
Related errors
- This profile is already active
- No note with id ${id}
- No supported provider found!
- Item not found: ${itemId}
- Unsupported item type for links: ${item.type_}
AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12).
Data as JSON: /api/errors/5389e8686eca4f04.
Report an issue: GitHub.