laurent22/joplin · error · Error

No notes selected for pdf export

Error message

No notes selected for pdf export

What it means

Thrown by the exportPdf command when noteIds resolves to an empty array. The command reads selectedNoteIds from context state (or an explicit argument) and requires at least one note to render to PDF.

Source

Thrown at packages/app-desktop/gui/WindowCommandsAndDialogs/commands/exportPdf.ts:20

import shim from '@joplin/lib/shim';
import InteropServiceHelper from '../../../InteropServiceHelper';
import { _ } from '@joplin/lib/locale';
import Note from '@joplin/lib/models/Note';
import bridge from '../../../services/bridge';
import { WindowControl } from '../utils/useWindowControl';

export const declaration: CommandDeclaration = {
	name: 'exportPdf',
	label: () => `PDF - ${_('PDF File')}`,
};

export const runtime = (comp: WindowControl): CommandRuntime => {
	return {
		execute: async (context: CommandContext, noteIds: string[] = null) => {
			try {
				noteIds = noteIds || context.state.selectedNoteIds;

				if (!noteIds.length) throw new Error('No notes selected for pdf export');

				let path = null;
				if (noteIds.length === 1) {
					path = await bridge().showSaveDialog({
						filters: [{ name: _('PDF File'), extensions: ['pdf'] }],
						defaultPath: await InteropServiceHelper.defaultFilename(noteIds[0], 'pdf'),
					});
				} else {
					path = await bridge().showOpenDialog({
						properties: ['openDirectory', 'createDirectory'],
					});
				}

				if (Array.isArray(path)) {
					if (path.length > 1) {
						throw new Error('Only one output directory can be selected');
					}

View on GitHub (pinned to 2654b33620)

Solutions

  1. Select at least one note in the note list before triggering PDF export.
  2. If invoking programmatically, pass an explicit non-empty noteIds array.
  3. Gate the UI action behind a 'someNotesSelected' enabled condition so the command cannot fire with no selection.
  4. Check context.state.selectedNoteIds.length before calling execute().

Example fix

// before
noteIds = noteIds || context.state.selectedNoteIds;
if (!noteIds.length) throw new Error('No notes selected for pdf export');

// after — disabled-condition style guard at the call site
if (!noteIds || noteIds.length === 0) {
  throw new Error('No notes selected for pdf export. Select at least one note and retry.');
}
Defensive patterns

Strategy: validation

Validate before calling

const ids = noteIds || context.state.selectedNoteIds;
if (!ids || ids.length === 0) {
  // prompt user to select a note, or abort
  return;
}
await CommandService.instance().execute('exportPdf', ids);

Type guard

function hasNotesToExport(ids: string[] | null | undefined): ids is string[] {
  return Array.isArray(ids) && ids.length > 0;
}

Try / catch

try {
  await CommandService.instance().execute('exportPdf', noteIds);
} catch (e) {
  if (e.message === 'No notes selected for pdf export') {
    // inform user to select at least one note
  } else throw e;
}

Prevention

When it happens

Trigger: Executing exportPdf when context.state.selectedNoteIds is empty AND no noteIds argument was passed, or when an explicit empty array is passed. The guard `if (!noteIds.length)` fires immediately.

Common situations: The command is invoked via keyboard shortcut/menu with no note selected in the list; a plugin calls execute() without arguments while the user has deselected all notes; the note list failed to populate a selection.

Related errors


AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12). Data as JSON: /api/errors/0067ebf5ce6a1c80. Report an issue: GitHub.