laurent22/joplin · warning · Error

Unable to scroll to hash -- no note open.

Error message

Unable to scroll to hash -- no note open.

What it means

Thrown by the scrollToHash command when context.state.selectedNoteIds is empty. Scrolling to an anchor/hash requires an open note; with nothing selected there is no note to scroll within.

Source

Thrown at packages/app-mobile/commands/scrollToHash.ts:13

import { CommandContext, CommandDeclaration, CommandRuntime } from '@joplin/lib/services/CommandService';
import NavService from '@joplin/lib/services/NavService';

export const declaration: CommandDeclaration = {
	name: 'scrollToHash',
};

export const runtime = (): CommandRuntime => {
	return {
		execute: async (context: CommandContext, hash: string) => {
			const selectedNoteIds = context.state.selectedNoteIds;
			if (selectedNoteIds.length === 0) {
				throw new Error('Unable to scroll to hash -- no note open.');
			}

			await NavService.go('Note', {
				noteId: selectedNoteIds[0],
				noteHash: hash,
			});
		},
	};
};

View on GitHub (pinned to 2654b33620)

Solutions

  1. Ensure a note is selected/open before triggering scrollToHash.
  2. If arriving from a deep link, open the target note first, then scroll.
  3. Gate the command behind an enabledCondition of `someNotesSelected`.
  4. Catch and ignore (or open the note) instead of throwing when no note is selected.

Example fix

// before
if (selectedNoteIds.length === 0) {
  throw new Error('Unable to scroll to hash -- no note open.');
}

// after — no-op with optional fallback navigation
if (selectedNoteIds.length === 0) {
  logger.warn('scrollToHash called with no open note; ignoring.');
  return;
}
Defensive patterns

Strategy: validation

Validate before calling

if (context.state.selectedNoteIds.length === 0) {
  // no open note — open one first, or skip
  return;
}
await CommandService.instance().execute('scrollToHash', hash);

Type guard

function hasOpenNote(selectedNoteIds: string[]): boolean {
  return Array.isArray(selectedNoteIds) && selectedNoteIds.length > 0;
}

Try / catch

try {
  await CommandService.instance().execute('scrollToHash', hash);
} catch (e) {
  if (e.message.includes('no note open')) {
    // open the target note first, then re-scroll
  } else throw e;
}

Prevention

When it happens

Trigger: Executing scrollToHash when the user has no note open (selectedNoteIds.length === 0). The guard fires before NavService.go, preventing navigation to a Note route with no noteId.

Common situations: A deep link / notification carrying a hash fires scrollToHash before any note is opened; the user returned to the notebook list; a plugin triggers scroll-to-hash programmatically without first opening a note.

Related errors


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