{"record":{"id":"efce600721488abf","repo":"laurent22/joplin","slug":"missing-item-id","errorCode":null,"errorMessage":"Missing item ID","messagePattern":"Missing item ID","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/app-mobile/commands/openItem.ts","lineNumber":55,"sourceCode":"};\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\n\t\t\ttry {\n\t\t\t\tif (link.startsWith('joplin://') || link.startsWith(':/')) {\n\t\t\t\t\tconst parsedResourceUrl = parseResourceUrl(link);\n\t\t\t\t\tconst parsedCallbackUrl = isCallbackUrl(link) ? parseCallbackUrl(link) : null;\n\n\t\t\t\t\tif (parsedResourceUrl) {\n\t\t\t\t\t\tconst { itemId, hash } = parsedResourceUrl;\n\t\t\t\t\t\tawait openItemById(itemId, hash);\n\t\t\t\t\t} else if (parsedCallbackUrl) {\n\t\t\t\t\t\tconst id = parsedCallbackUrl.params.id;\n\t\t\t\t\t\tif (!id) {\n\t\t\t\t\t\t\tthrow new Error('Missing item ID');\n\t\t\t\t\t\t}\n\t\t\t\t\t\tawait openItemById(id);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow new Error('Unsupported link format.');\n\t\t\t\t\t}\n\t\t\t\t} else if (urlProtocol(link)) {\n\t\t\t\t\tshim.openUrl(link);\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error('Unsupported protocol');\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst errorMessage = _('Unsupported link or message: %s.\\nError: %s', link, error);\n\t\t\t\tlogger.error(errorMessage);\n\t\t\t\tawait shim.showErrorDialog(errorMessage);\n\t\t\t}\n\t\t},\n\t};\n};","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/laurent22/joplin/blob/2654b33620775080d1d59c552259d41e33dad3d2/packages/app-mobile/commands/openItem.ts#L37-L73","documentation":"Thrown when a parsed Joplin callback URL (isCallbackUrl was true and parseCallbackUrl succeeded) has no `id` parameter in its params. The callback-URL branch needs an id to locate the target item; without it, openItemById cannot be called.","triggerScenarios":"A link matching the callback-URL shape (e.g. joplin://x-callback-url/open) parses successfully but its query params lack `id`. The `if (!id)` guard fires.","commonSituations":"A malformed or truncated callback URL; a callback URL built by a third-party tool that omits the required id param; copy-paste truncation dropping the id query segment.","solutions":["Inspect the full callback URL and confirm it includes an `id` query parameter.","Regenerate the link from Joplin's built-in 'copy link' to ensure correct params.","If building callback URLs, always include `id`.","Catch the error and prompt the user for a valid link."],"exampleFix":"// before\nconst id = parsedCallbackUrl.params.id;\nif (!id) throw new Error('Missing item ID');\n\n// after — include the offending URL for diagnosis\nconst id = parsedCallbackUrl.params.id;\nif (!id) throw new Error(`Missing item ID in callback URL: ${link}`);","handlingStrategy":"validation","validationCode":"const parsed = isCallbackUrl(link) ? parseCallbackUrl(link) : null;\nif (parsed && !parsed.params.id) {\n  // reject the callback URL before navigation\n  throw new Error(`Callback URL missing id: ${link}`);\n}","typeGuard":"function callbackUrlHasId(parsed: { params: Record<string, string> } | null): boolean {\n  return parsed != null && typeof parsed.params.id === 'string' && parsed.params.id.length > 0;\n}","tryCatchPattern":"try {\n  await CommandService.instance().execute('openItem', link);\n} catch (e) {\n  if (e.message === 'Missing item ID') {\n    // prompt user for a valid callback URL\n  } else throw e;\n}","preventionTips":["When building callback URLs, always include the `id` parameter.","Use Joplin's own 'copy link' to generate well-formed callback URLs.","Validate parsed.params.id before attempting navigation."],"tags":["mobile","links","callback-url","validation"],"backgroundTag":null,"analyzedSha":"2654b33620775080d1d59c552259d41e33dad3d2","analyzedAt":"2026-08-12T14:26:46.263Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}