laurent22/joplin · error · Error
Locked notes cannot be opened in an external editor
Error message
Locked notes cannot be opened in an external editor
What it means
Thrown by the startExternalEditing command when EEE (Encryption Master Password / note lock) is enabled and the target note has is_locked true. Locked notes are encrypted at rest; opening them in an external editor would either expose ciphertext to the editor process or let plaintext be written to an unencrypted temp file, so the command refuses.
Source
Thrown at packages/app-desktop/commands/startExternalEditing.ts:24
import isNoteLockEnabled from '@joplin/lib/services/noteLock/isNoteLockEnabled';
import bridge from '../services/bridge';
export const declaration: CommandDeclaration = {
name: 'startExternalEditing',
label: () => _('Open in external editor'),
iconName: 'icon-share',
};
export const runtime = (): CommandRuntime => {
return {
execute: async (context: CommandContext, noteId: string = null) => {
noteId = noteId || stateUtils.selectedNoteId(context.state);
try {
const note = await Note.load(noteId);
// The enabled condition can be bypassed when the command is executed directly (e.g. via
// toggleExternalEditing): the external editor would get ciphertext, or write plaintext to disk.
if (isNoteLockEnabled() && note.is_locked) throw new Error(_('Locked notes cannot be opened in an external editor'));
void ExternalEditWatcher.instance().openAndWatch(note);
} catch (error) {
bridge().showErrorMessageBox(_('Error opening note in editor: %s', error.message));
}
},
enabledCondition: 'oneNoteSelected && !noteIsReadOnly && !noteIsLocked',
};
};
View on GitHub (pinned to 2654b33620)
Solutions
- Unlock the note (remove is_locked) before launching the external editor.
- Disable note locking (clear the master password / lock feature) if external editing is required for that note.
- Route calls through the command service so enabledCondition (`!noteIsLocked`) disables the action rather than throwing.
- In a plugin, check note.is_locked and isNoteLockEnabled() before calling execute().
Example fix
// before
if (isNoteLockEnabled() && note.is_locked) throw new Error(_('Locked notes cannot be opened in an external editor'));
// after — guard before invoking, surface a user-actionable hint
if (isNoteLockEnabled() && note.is_locked) {
throw new Error(_('Locked notes cannot be opened in an external editor. Unlock the note first.'));
} Defensive patterns
Strategy: validation
Validate before calling
const note = await Note.load(noteId);
if (isNoteLockEnabled() && note?.is_locked) {
// ask user to unlock, or abort — do not call startExternalEditing
return;
}
await CommandService.instance().execute('startExternalEditing', noteId); Type guard
function canOpenInExternalEditor(note: NoteEntity | null): boolean {
return !!note && !(isNoteLockEnabled() && note.is_locked);
} Try / catch
try {
await CommandService.instance().execute('startExternalEditing', noteId);
} catch (e) {
if (e.message.includes('Locked notes')) {
// prompt the user to unlock the note first
} else throw e;
} Prevention
- Route external-edit invocations through the command service so enabledCondition (!noteIsLocked) disables the action.
- Check isNoteLockEnabled() and note.is_locked before any direct execute() call.
- Unlock notes before launching external editing when EEE is on.
When it happens
Trigger: Executing startExternalEditing (directly or via toggleExternalEditing) on a note where isNoteLockEnabled() returns true AND note.is_locked is true. The enabledCondition already excludes locked notes, but a direct execute() call bypasses enabled checks, hence the in-body guard.
Common situations: A toolbar/keyboard shortcut wired directly to execute() instead of going through the enabled-condition gate; programmatic command invocation from a plugin; the note was locked after the menu was rendered so the enabled state is stale.
Related errors
- Encrypted items cannot be modified
- Format "${format}" can only be exported to a file
- No notes selected for pdf export
- Only one output directory can be selected
- Cannot move item with type ${itemType}
AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12).
Data as JSON: /api/errors/900c8472f51fdd96.
Report an issue: GitHub.