{"record":{"id":"b37e30384ee2d2f9","repo":"laurent22/joplin","slug":"invalid-callback-url-s","errorCode":null,"errorMessage":"Invalid callback url ${s}","messagePattern":"Invalid callback url (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/lib/callbackUrlUtils.ts","lineNumber":37,"sourceCode":"export function getTagCallbackUrl(tagId: string) {\n\treturn `joplin://x-callback-url/openTag?id=${encodeURIComponent(tagId)}`;\n}\n\nexport const enum CallbackUrlCommand {\n\tOpenNote = 'openNote',\n\tOpenFolder = 'openFolder',\n\tOpenTag = 'openTag',\n\tGetCurrentNote = 'getCurrentNote',\n\tCreateNote = 'createNote',\n}\n\nexport interface CallbackUrlInfo {\n\tcommand: CallbackUrlCommand;\n\tparams: Record<string, string>;\n}\n\nexport function parseCallbackUrl(s: string): CallbackUrlInfo {\n\tif (!isCallbackUrl(s)) throw new Error(`Invalid callback url ${s}`);\n\tconst url = new URL(s, true);\n\treturn {\n\t\tcommand: url.pathname.substring(url.pathname.lastIndexOf('/') + 1) as CallbackUrlCommand,\n\t\tparams: url.query,\n\t};\n}\n","sourceCodeStart":19,"sourceCodeEnd":44,"githubUrl":"https://github.com/laurent22/joplin/blob/2654b33620775080d1d59c552259d41e33dad3d2/packages/lib/callbackUrlUtils.ts#L19-L44","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nimport { parseCallbackUrl } from './callbackUrlUtils';\nconst info = parseCallbackUrl(raw); // throws if raw is not a callback url\n\n// after\nimport { isCallbackUrl, parseCallbackUrl } from './callbackUrlUtils';\nif (!isCallbackUrl(raw)) {\n  // handle a regular joplin:// link or reject input\n  return;\n}\nconst info = parseCallbackUrl(raw);","handlingStrategy":"type-guard","validationCode":"import { isCallbackUrl } from './callbackUrlUtils';\nif (!isCallbackUrl(candidate)) {\n  // reject or branch for non-callback URLs\n  return null;\n}\nconst info = parseCallbackUrl(candidate);","typeGuard":"import { isCallbackUrl } from './callbackUrlUtils';\nfunction isParsableCallbackUrl(s: string): s is string {\n  return typeof s === 'string' && isCallbackUrl(s);\n}","tryCatchPattern":"try {\n  const info = parseCallbackUrl(raw);\n} catch (error) {\n  if (/Invalid callback url/.test(error.message)) {\n    // handle a regular joplin:// link or invalid input\n    return;\n  }\n  throw error;\n}","preventionTips":["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."],"tags":["callback-url","validation","x-callback-url","url-parsing"],"backgroundTag":null,"analyzedSha":"2654b33620775080d1d59c552259d41e33dad3d2","analyzedAt":"2026-08-12T14:26:46.263Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}