laurent22/joplin · error · Error

Invalid callback url ${s}

Error message

Invalid callback url ${s}

What it means

Thrown by parseCallbackUrl() when the input string does not pass isCallbackUrl(), which checks for one of five exact scheme+path prefixes: joplin://x-callback-url/openNote|, openFolder|, openTag|, getCurrentNote|, createNote?. The function is strict about the prefix; any other scheme (http://, joplin:// without x-callback-url, a trailing path mismatch) is rejected.

Source

Thrown at packages/lib/callbackUrlUtils.ts:37

export function getTagCallbackUrl(tagId: string) {
	return `joplin://x-callback-url/openTag?id=${encodeURIComponent(tagId)}`;
}

export const enum CallbackUrlCommand {
	OpenNote = 'openNote',
	OpenFolder = 'openFolder',
	OpenTag = 'openTag',
	GetCurrentNote = 'getCurrentNote',
	CreateNote = 'createNote',
}

export interface CallbackUrlInfo {
	command: CallbackUrlCommand;
	params: Record<string, string>;
}

export function parseCallbackUrl(s: string): CallbackUrlInfo {
	if (!isCallbackUrl(s)) throw new Error(`Invalid callback url ${s}`);
	const url = new URL(s, true);
	return {
		command: url.pathname.substring(url.pathname.lastIndexOf('/') + 1) as CallbackUrlCommand,
		params: url.query,
	};
}

View on GitHub (pinned to 2654b33620)

Solutions

  1. Pre-validate with isCallbackUrl(s) before calling parseCallbackUrl(s).
  2. Construct callback URLs via the provided helpers getNoteCallbackUrl/getFolderCallbackUrl/getTagCallbackUrl rather than hand-building strings.
  3. If you need to handle non-callback joplin:// links, branch on the scheme before calling parseCallbackUrl.

Example fix

// before
import { parseCallbackUrl } from './callbackUrlUtils';
const info = parseCallbackUrl(raw); // throws if raw is not a callback url

// after
import { isCallbackUrl, parseCallbackUrl } from './callbackUrlUtils';
if (!isCallbackUrl(raw)) {
  // handle a regular joplin:// link or reject input
  return;
}
const info = parseCallbackUrl(raw);
Defensive patterns

Strategy: type-guard

Validate before calling

import { isCallbackUrl } from './callbackUrlUtils';
if (!isCallbackUrl(candidate)) {
  // reject or branch for non-callback URLs
  return null;
}
const info = parseCallbackUrl(candidate);

Type guard

import { isCallbackUrl } from './callbackUrlUtils';
function isParsableCallbackUrl(s: string): s is string {
  return typeof s === 'string' && isCallbackUrl(s);
}

Try / catch

try {
  const info = parseCallbackUrl(raw);
} catch (error) {
  if (/Invalid callback url/.test(error.message)) {
    // handle a regular joplin:// link or invalid input
    return;
  }
  throw error;
}

Prevention

When it happens

Trigger: Calling parseCallbackUrl(s) with a string that is not one of the five recognised joplin://x-callback-url/... URLs — e.g. a plain 'joplin://...' note link, an http URL, a malformed callback string, or a URL with a different command path.

Common situations: Passing a regular internal Joplin link (:/id) instead of an x-callback-url; user-pasted or plugin-supplied URLs that don't match the prefix; typos in the command segment; integrating with third-party apps that send a slightly different scheme.

Related errors


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