{"record":{"id":"985fa22a9e53ebeb","repo":"laurent22/joplin","slug":"item-not-found-itemid","errorCode":null,"errorMessage":"Item not found: ${itemId}","messagePattern":"Item not found: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/app-mobile/commands/openItem.ts","lineNumber":25,"sourceCode":"import BaseItem from '@joplin/lib/models/BaseItem';\nimport { BaseItemEntity } from '@joplin/lib/services/database/types';\nimport { ModelType } from '@joplin/lib/BaseModel';\nimport showResource from './util/showResource';\nimport { isCallbackUrl, parseCallbackUrl } from '@joplin/lib/callbackUrlUtils';\nimport goToFolder from './util/goToFolder';\n\nconst logger = Logger.create('openItemCommand');\n\nexport const declaration: CommandDeclaration = {\n\tname: 'openItem',\n};\n\nconst openItemById = async (itemId: string, hash?: string) => {\n\tlogger.info(`Navigating to item ${itemId}`);\n\tconst item: BaseItemEntity = await BaseItem.loadItemById(itemId);\n\n\tif (!item) {\n\t\tthrow new Error(`Item not found: ${itemId}`);\n\t}\n\n\tif (item.type_ === ModelType.Note) {\n\t\tawait goToNote(itemId, hash);\n\t} else if (item.type_ === ModelType.Resource) {\n\t\tawait showResource(item);\n\t} else if (item.type_ === ModelType.Folder) {\n\t\tawait goToFolder(item.id);\n\t} else {\n\t\tthrow new Error(`Unsupported item type for links: ${item.type_}`);\n\t}\n};\n\nexport const runtime = (): CommandRuntime => {\n\treturn {\n\t\texecute: async (_context: CommandContext, link: string) => {\n\t\t\tif (!link) throw new Error('Link cannot be empty');\n","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/laurent22/joplin/blob/2654b33620775080d1d59c552259d41e33dad3d2/packages/app-mobile/commands/openItem.ts#L7-L43","documentation":"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.","triggerScenarios":"A joplin:// or :/ link (resource URL or callback URL) carries an itemId; openItemById loads it; loadItemById returns null/undefined; the `if (!item)` guard throws.","commonSituations":"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.","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."],"exampleFix":"// before\nconst item = await BaseItem.loadItemById(itemId);\nif (!item) throw new Error(`Item not found: ${itemId}`);\n\n// after — softer UX with sync hint\nconst item = await BaseItem.loadItemById(itemId);\nif (!item) throw new Error(`Item not found: ${itemId}. It may have been deleted or not yet synced.`);","handlingStrategy":"validation","validationCode":"const item = await BaseItem.loadItemById(itemId);\nif (!item) {\n  // maybe not synced yet — sync then retry, or inform user\n  await reg.syncAll();\n  if (!(await BaseItem.loadItemById(itemId))) return;\n}","typeGuard":"function itemExists(item: BaseItemEntity | null): item is BaseItemEntity {\n  return item != null;\n}","tryCatchPattern":"try {\n  await openItemById(itemId);\n} catch (e) {\n  if (e.message.startsWith('Item not found')) {\n    // sync, then retry once; else show 'link target unavailable'\n  } else throw e;\n}","preventionTips":["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."],"tags":["mobile","links","item-lookup","validation","sync"],"backgroundTag":null,"analyzedSha":"2654b33620775080d1d59c552259d41e33dad3d2","analyzedAt":"2026-08-12T14:26:46.263Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}