Summary
On Firefox/Zen, the obsidian:// handoff silently fails on any profile that has not
disabled the external-protocol confirmation. Both the popup's Devour and the bridge's
tab_clip are affected: extraction succeeds, the tool reports success with a file path,
and no note is ever written.
This has been invisible in development because bun run start launches the dev profile
with the two prefs that suppress the confirmation. A user installing from AMO gets the
failing path.
Cause
openObsidianUrl (src/background.ts) launches the protocol into a background tab and
destroys it 500ms later:
const ephemeral = await browser.tabs.create({ url: launchUrl, active: false });
if (ephemeral.id !== undefined) {
const ephemeralId = ephemeral.id;
setTimeout(() => { void browser.tabs.remove(ephemeralId).catch(() => {}); }, 500);
}
When Firefox wants to confirm the launch, the confirmation is raised against a tab that is
never visible and is gone before it could be answered. The launch is discarded with no
error surfaced to either the popup or the bridge.
package.json's start script sets:
--pref=network.protocol-handler.external.obsidian=true
--pref=network.protocol-handler.warn-external.obsidian=false
so the dialog never appears in dev. A real profile has neither pref.
Reproduction
- Use a Firefox/Zen profile without
network.protocol-handler.warn-external.obsidian=false.
(handlers.json holding obsidian: {"action": 4} is not sufficient — there is no
ask: false alongside it.)
- Devour any tab from the popup, or call
tab_clip over the bridge.
- Extraction succeeds and the call reports success; no note appears in any vault.
Setting both prefs manually in about:config makes it work immediately, which confirms
the diagnosis. Obsidian additionally shows a one-time "trust this source / allow the new
command" prompt on first successful launch; that one is expected and is not part of this bug.
Verified on Zen 1.21.9b, extension 0.2.0.2, macOS. Driving the same URL through
open "obsidian://new?file=...&vault=...&content=..." writes the note correctly, which
isolates the failure to the browser-side launch rather than to Obsidian or the URL builder.
Why the pref is not the fix
Telling users to set an about:config pref is not a shippable remedy for a store build.
The structural problem is that the launch is fired into a background tab that is
immediately destroyed, which discards any confirmation UI the browser needs to show — and
with it the "always allow" checkbox that would make subsequent launches silent.
Chrome already solves the equivalent problem by launching from the extension-origin page
redirect/obsidian-redirect.html, so the one-time approval is rememberable. Firefox
currently bypasses that page entirely and launches the protocol directly.
Secondary issue
tab_clip reports success without any confirmation that Obsidian received the handoff — it
returns the path it intended to write. That is how this bug stayed silent. It matters more
for tab_clip({ close: true }), which would close the tab on the strength of that
unverified success, filing a tab into the void and then closing it.
Scope
Pre-existing; unrelated to the vault-override (#16) or global-config (#17) work, both of
which are otherwise verified working.
Summary
On Firefox/Zen, the
obsidian://handoff silently fails on any profile that has notdisabled the external-protocol confirmation. Both the popup's Devour and the bridge's
tab_clipare affected: extraction succeeds, the tool reports success with a file path,and no note is ever written.
This has been invisible in development because
bun run startlaunches the dev profilewith the two prefs that suppress the confirmation. A user installing from AMO gets the
failing path.
Cause
openObsidianUrl(src/background.ts) launches the protocol into a background tab anddestroys it 500ms later:
When Firefox wants to confirm the launch, the confirmation is raised against a tab that is
never visible and is gone before it could be answered. The launch is discarded with no
error surfaced to either the popup or the bridge.
package.json'sstartscript sets:so the dialog never appears in dev. A real profile has neither pref.
Reproduction
network.protocol-handler.warn-external.obsidian=false.(
handlers.jsonholdingobsidian: {"action": 4}is not sufficient — there is noask: falsealongside it.)tab_clipover the bridge.Setting both prefs manually in
about:configmakes it work immediately, which confirmsthe diagnosis. Obsidian additionally shows a one-time "trust this source / allow the
newcommand" prompt on first successful launch; that one is expected and is not part of this bug.
Verified on Zen 1.21.9b, extension 0.2.0.2, macOS. Driving the same URL through
open "obsidian://new?file=...&vault=...&content=..."writes the note correctly, whichisolates the failure to the browser-side launch rather than to Obsidian or the URL builder.
Why the pref is not the fix
Telling users to set an
about:configpref is not a shippable remedy for a store build.The structural problem is that the launch is fired into a background tab that is
immediately destroyed, which discards any confirmation UI the browser needs to show — and
with it the "always allow" checkbox that would make subsequent launches silent.
Chrome already solves the equivalent problem by launching from the extension-origin page
redirect/obsidian-redirect.html, so the one-time approval is rememberable. Firefoxcurrently bypasses that page entirely and launches the protocol directly.
Secondary issue
tab_clipreports success without any confirmation that Obsidian received the handoff — itreturns the path it intended to write. That is how this bug stayed silent. It matters more
for
tab_clip({ close: true }), which would close the tab on the strength of thatunverified success, filing a tab into the void and then closing it.
Scope
Pre-existing; unrelated to the vault-override (#16) or global-config (#17) work, both of
which are otherwise verified working.