laurent22/joplin · error · Error
Item not found: ${itemId}
Error message
Item not found: ${itemId} What it means
Thrown by openItemById when BaseItem.loadItemById(itemId) returns a falsy value. The command resolved a link to an item ID but no record with that ID exists (or is not visible) in the local database, so navigation cannot proceed.
Source
Thrown at packages/app-mobile/commands/openItem.ts:25
import BaseItem from '@joplin/lib/models/BaseItem';
import { BaseItemEntity } from '@joplin/lib/services/database/types';
import { ModelType } from '@joplin/lib/BaseModel';
import showResource from './util/showResource';
import { isCallbackUrl, parseCallbackUrl } from '@joplin/lib/callbackUrlUtils';
import goToFolder from './util/goToFolder';
const logger = Logger.create('openItemCommand');
export const declaration: CommandDeclaration = {
name: 'openItem',
};
const openItemById = async (itemId: string, hash?: string) => {
logger.info(`Navigating to item ${itemId}`);
const item: BaseItemEntity = await BaseItem.loadItemById(itemId);
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');
View on GitHub (pinned to 2654b33620)
Solutions
- Sync to ensure the referenced item is downloaded to this device.
- Verify the itemId in the link matches an existing record (query the DB).
- Remove or fix the stale link in the source note.
- Catch the error and show a 'link target not found' message instead of crashing.
Example fix
// before
const item = await BaseItem.loadItemById(itemId);
if (!item) throw new Error(`Item not found: ${itemId}`);
// after — softer UX with sync hint
const item = await BaseItem.loadItemById(itemId);
if (!item) throw new Error(`Item not found: ${itemId}. It may have been deleted or not yet synced.`); Defensive patterns
Strategy: validation
Validate before calling
const item = await BaseItem.loadItemById(itemId);
if (!item) {
// maybe not synced yet — sync then retry, or inform user
await reg.syncAll();
if (!(await BaseItem.loadItemById(itemId))) return;
} Type guard
function itemExists(item: BaseItemEntity | null): item is BaseItemEntity {
return item != null;
} Try / catch
try {
await openItemById(itemId);
} catch (e) {
if (e.message.startsWith('Item not found')) {
// sync, then retry once; else show 'link target unavailable'
} else throw e;
} Prevention
- Sync before resolving links from other devices.
- Validate item IDs against the DB before navigating.
- Surface a friendly 'not found' message rather than a raw stack.
When it happens
Trigger: A joplin:// or :/ link (resource URL or callback URL) carries an itemId; openItemById loads it; loadItemById returns null/undefined; the `if (!item)` guard throws.
Common situations: Following a link to a note/resource/folder that was deleted; the item has not yet synced to this device; the link contains a stale or wrong ID; cross-profile links where the ID exists in another profile's DB.
Related errors
- Unsupported item type for links: ${item.type_}
- Link cannot be empty
- Missing item ID
- Unsupported link format.
- Unsupported protocol
AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12).
Data as JSON: /api/errors/985fa22a9e53ebeb.
Report an issue: GitHub.