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
- Pre-validate with isCallbackUrl(s) before calling parseCallbackUrl(s).
- Construct callback URLs via the provided helpers getNoteCallbackUrl/getFolderCallbackUrl/getTagCallbackUrl rather than hand-building strings.
- 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
- Always call isCallbackUrl() before parseCallbackUrl().
- Build callback URLs with the provided getNoteCallbackUrl/getFolderCallbackUrl/getTagCallbackUrl helpers.
- Validate external/plugin-supplied URLs at the trust boundary before parsing.
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.