tw93/Pake · info
Cannot open special URL with shell:
Error message
Cannot open special URL with shell:
What it means
handleExternalLink opens non-internal URLs in the system browser via the Tauri shell plugin (`invoke("plugin:shell|open")`). Before doing so it checks isSpecialDownload(url), which matches blob:, data:, and similar special-scheme URLs. If the URL is special, the function deliberately refuses to hand it to the OS shell and logs this warning instead — blob/data URLs cannot be opened by the OS and attempting to would fail or misbehave.
Solutions
- This is expected behavior for blob:/data: URLs — the page's own download handling (anchor `download` attribute) should process them; ensure the click is not being intercepted before the browser's native download logic runs.
- If the blob should be saved as a file, create an anchor element with the blob URL and a `download` attribute and click it programmatically, rather than routing it to the shell plugin.
- If a legitimate http(s) link is being misclassified, inspect isSpecialDownload's matching and the URL construction — an empty-string or null href coerced into a special-looking URL can trigger the guard.
- For apps that must export files externally, offer the http(s) CDN URL of the asset instead of a blob URL so the shell open path works.
Example fix
// before
const handleExternalLink = (url) => {
if (isSpecialDownload(url)) {
console.warn("Cannot open special URL with shell:", url);
return;
}
invoke("plugin:shell|open", { path: url });
// after (route blob URLs to a native browser download instead of refusing silently)
const handleExternalLink = (url, anchorElement) => {
if (isSpecialDownload(url)) {
if (anchorElement?.download) return; // let the anchor's download attribute handle it
const a = document.createElement("a");
a.href = url;
a.download = "";
a.click();
return;
}
invoke("plugin:shell|open", { path: url }); Defensive patterns
Strategy: fallback
Validate before calling
function isOpenableWithShell(url) {
try {
const scheme = new URL(url, location.href).protocol;
return scheme === "http:" || scheme === "https:";
} catch {
return false;
}
} Type guard
const isHttpUrl = (url) => {
try { return /^https?:$/.test(new URL(url, location.href).protocol); }
catch { return false; }
}; Try / catch
invoke("plugin:shell|open", { path: url }).catch((error) => {
console.warn("Shell open failed, falling back to anchor:", error);
const a = document.createElement("a");
a.href = url;
a.target = "_blank";
a.rel = "noopener";
a.click();
}); Prevention
- Check the URL scheme with the URL API before invoking plugin:shell|open.
- Treat blob:/data: URLs as download candidates via anchor[download], not external navigation.
- Verify the shell:allow-open permission exists in capabilities when wiring external links.
- Test export/preview features of the target site — client-side blob downloads are the most common special-URL case.
When it happens
Trigger: A user clicks (or the page triggers) an external link whose href is a `blob:` URL (common for client-generated downloads, PDF previews, or media streams) or a `data:` URL (inline CSV/Base64 downloads). The special-scheme check short-circuits and prints "Cannot open special URL with shell:" before any shell invoke happens.
Common situations: Clicking an 'Export as PDF/CSV' button on a web app that generates the file client-side as a blob; opening a preview of an uploaded document served as a blob URL; sites that build `data:text/csv,...` download links; canvas/image 'download' buttons that create object URLs at click time.
Related errors
AI-assisted analysis of tw93/Pake@c8fe8a3f1a (2026-09-20).
Data as JSON: /api/errors/288c03655cea70ec.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/src/inject/event.js:716
document.body.appendChild(anchor);
anchor.click();
document.body.removeChild(anchor);
}
// process special download protocol['data:','blob:']
const isSpecialDownload = (url) =>
["blob", "data"].some((protocol) => url.startsWith(protocol));
// Cmd/Ctrl+click is a browser "open related" gesture, not "save as".
// Only the download attribute and downloadable-file heuristics force a
// download; modifiers must not rewrite ordinary navigation.
const isDownloadRequired = (url, anchorElement, _e) =>
Boolean(anchorElement.download) || isDownloadableFile(url);
const handleExternalLink = (url) => {
// Don't try to open blob: or data: URLs with shell
if (isSpecialDownload(url)) {
console.warn("Cannot open special URL with shell:", url);
return;
}
invoke("plugin:shell|open", {
path: url,
}).catch((error) => {
console.error("Failed to open URL with shell:", url, error);
});
};
const isInternalUrl = (url) => matchesInternalUrl(url, window.location.href);
const detectAnchorElementClick = (e) => {
// Safety check: ensure e.target exists and is an Element with closest method
if (!e.target || typeof e.target.closest !== "function") {
return;
}
const anchorElement = e.target.closest("a");View on GitHub (pinned to c8fe8a3f1a)