laurent22/joplin · error · Error

Missing item ID

Error message

Missing item ID

What it means

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.

Source

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

};

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.');
					}
				} else if (urlProtocol(link)) {
					shim.openUrl(link);
				} else {
					throw new Error('Unsupported protocol');
				}
			} catch (error) {
				const errorMessage = _('Unsupported link or message: %s.\nError: %s', link, error);
				logger.error(errorMessage);
				await shim.showErrorDialog(errorMessage);
			}
		},
	};
};

View on GitHub (pinned to 2654b33620)

Solutions

  1. Inspect the full callback URL and confirm it includes an `id` query parameter.
  2. Regenerate the link from Joplin's built-in 'copy link' to ensure correct params.
  3. If building callback URLs, always include `id`.
  4. Catch the error and prompt the user for a valid link.

Example fix

// before
const id = parsedCallbackUrl.params.id;
if (!id) throw new Error('Missing item ID');

// after — include the offending URL for diagnosis
const id = parsedCallbackUrl.params.id;
if (!id) throw new Error(`Missing item ID in callback URL: ${link}`);
Defensive patterns

Strategy: validation

Validate before calling

const parsed = isCallbackUrl(link) ? parseCallbackUrl(link) : null;
if (parsed && !parsed.params.id) {
  // reject the callback URL before navigation
  throw new Error(`Callback URL missing id: ${link}`);
}

Type guard

function callbackUrlHasId(parsed: { params: Record<string, string> } | null): boolean {
  return parsed != null && typeof parsed.params.id === 'string' && parsed.params.id.length > 0;
}

Try / catch

try {
  await CommandService.instance().execute('openItem', link);
} catch (e) {
  if (e.message === 'Missing item ID') {
    // prompt user for a valid callback URL
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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