laurent22/joplin · error · Error

Please select a notebook first.

Error message

Please select a notebook first.

What it means

Thrown by `ls` inside the else-branch (pattern is not `/` AND a current notebook exists at the top check). The inner `if (!app().currentFolder())` guard is effectively dead code: the outer condition at line 60 (`pattern === '/' || !app().currentFolder()`) already routed the no-folder case to the folder-listing branch, and no await runs between the two checks, so currentFolder cannot become null in between. If ever hit, it means currentFolder was set to a falsy value mid-call.

Source

Thrown at packages/app-cli/app/command-ls.ts:65

			queryOptions.orderByDir = 'ASC';
		}
		if (options.reverse === true) queryOptions.orderByDir = queryOptions.orderByDir === 'ASC' ? 'DESC' : 'ASC';
		queryOptions.caseInsensitive = true;
		if (options.type) {
			queryOptions.itemTypes = [];
			if (options.type.indexOf('n') >= 0) queryOptions.itemTypes.push('note');
			if (options.type.indexOf('t') >= 0) queryOptions.itemTypes.push('todo');
		}
		if (pattern) queryOptions.titlePattern = pattern;
		queryOptions.uncompletedTodosOnTop = Setting.value('uncompletedTodosOnTop');

		let modelType = null;
		if (pattern === '/' || !app().currentFolder()) {
			queryOptions.includeConflictFolder = true;
			items = await Folder.all(queryOptions);
			modelType = Folder.modelType();
		} else {
			if (!app().currentFolder()) throw new Error(_('Please select a notebook first.'));
			items = await Note.previews(app().currentFolder().id, queryOptions);
			modelType = Note.modelType();
		}

		if (options.format && options.format === 'json') {
			this.stdout(JSON.stringify(items));
		} else {
			let hasTodos = false;
			for (let i = 0; i < items.length; i++) {
				const item = items[i];
				if ((item as NoteEntity).is_todo) {
					hasTodos = true;
					break;
				}
			}

			const seenTitles = [];
			const rows = [];

View on GitHub (pinned to 2654b33620)

Solutions

  1. Select a notebook: `joplin use <notebook>` then `joplin ls`
  2. If you genuinely see this message, file a bug — the upstream guard should have prevented it
  3. Run `joplin ls /` explicitly to list notebooks when unsure of selection state

Example fix

// before
joplin ls              // when no notebook is selected, lists folders instead (outer branch)

// after
joplin use Personal
joplin ls              // lists notes in Personal
Defensive patterns

Strategy: validation

Validate before calling

import app from './app';

// the throw is effectively unreachable (outer branch handles it), but guard anyway:
function assertNotebookSelectedForLs(): void {
  if (!app().currentFolder()) {
    throw new Error('Select a notebook first (`use <notebook>`), or run `ls /` to list notebooks.');
  }
}

Type guard

const hasSelectedNotebook = (): boolean => !!app().currentFolder();

Prevention

When it happens

Trigger: Not reachable through normal CLI usage because of the upstream short-circuit at line 60. Would only fire if a concurrent `switchCurrentFolder(null)` ran between the outer check and the inner check (single-threaded JS makes this impossible here).

Common situations: Never observed in practice; the error exists as a defensive invariant. Users hitting "no notebook" while listing notes are actually seeing folder output instead (the outer branch).

Related errors


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