laurent22/joplin · error · Error

Link cannot be empty

Error message

Link cannot be empty

What it means

Thrown at the top of the openItem command's execute() when the link argument is falsy. The command needs a string to parse and dispatch; an empty/null/undefined link cannot be processed.

Source

Thrown at packages/app-mobile/commands/openItem.ts:42

	if (!item) {
		throw new Error(`Item not found: ${itemId}`);
	}

	if (item.type_ === ModelType.Note) {
		await goToNote(itemId, hash);
	} else if (item.type_ === ModelType.Resource) {
		await showResource(item);
	} else if (item.type_ === ModelType.Folder) {
		await goToFolder(item.id);
	} else {
		throw new Error(`Unsupported item type for links: ${item.type_}`);
	}
};

export const runtime = (): CommandRuntime => {
	return {
		execute: async (_context: CommandContext, link: string) => {
			if (!link) throw new Error('Link cannot be empty');

			try {
				if (link.startsWith('joplin://') || link.startsWith(':/')) {
					const parsedResourceUrl = parseResourceUrl(link);
					const parsedCallbackUrl = isCallbackUrl(link) ? parseCallbackUrl(link) : null;

					if (parsedResourceUrl) {
						const { itemId, hash } = parsedResourceUrl;
						await openItemById(itemId, hash);
					} else if (parsedCallbackUrl) {
						const id = parsedCallbackUrl.params.id;
						if (!id) {
							throw new Error('Missing item ID');
						}
						await openItemById(id);
					} else {
						throw new Error('Unsupported link format.');
					}

View on GitHub (pinned to 2654b33620)

Solutions

  1. Ensure the caller always passes a non-empty link string.
  2. Guard at the call site: only invoke openItem when link is truthy.
  3. If the empty link is from a UI element, disable that element when no link is set.
  4. Catch and ignore silently if an empty link is a benign no-op in your flow.

Example fix

// before
execute: async (_context, link) => {
  if (!link) throw new Error('Link cannot be empty');

// after — no-op instead of throw for programmatic callers
execute: async (_context, link) => {
  if (!link) {
    logger.warn('openItem called with empty link; ignoring.');
    return;
  }
Defensive patterns

Strategy: validation

Validate before calling

if (!link || typeof link !== 'string' || link.trim().length === 0) {
  // do not call openItem — log and return
  return;
}
await CommandService.instance().execute('openItem', link);

Type guard

function isNonEmptyLink(link: unknown): link is string {
  return typeof link === 'string' && link.trim().length > 0;
}

Try / catch

try {
  await CommandService.instance().execute('openItem', link);
} catch (e) {
  if (e.message === 'Link cannot be empty') {
    // caller bug — fix the call site rather than retry
  } else throw e;
}

Prevention

When it happens

Trigger: Calling the openItem command's execute() with link = '' , null, or undefined. The `if (!link)` guard throws before any parsing.

Common situations: A programmatic caller (plugin, notification handler) invokes openItem without an argument; a note's link field is empty; a deep-link entry point fires with no URL payload.

Related errors


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