A wikilink whose target is only whitespace (e.g. [[ ]]) is treated as a link to the
current file, rather than as no link at all. [[]] with nothing between the
brackets is correctly left as literal text, so the two differ only by a space.
The embed form is the more serious case: ![[ ]] embeds the containing note into
itself, producing a self-embed.
Steps to reproduce
- Start Obsidian in a new vault with Restricted mode on (no plugins, default theme).
- Create a note
A.mdcontaining exactly:
[[ ]]
- Open the Backlinks pane for
A.md. - Create a second note
B.mdcontaining exactly:
![[ ]]
- View
B.mdin Reading mode.
Did you read and follow the Troubleshooting Guide ? Yes
Actual result
The whitespace-only forms are parsed as links to the current note, while the
empty forms are not:
| Source | Reading mode |
|---|---|
[[]] |
plain text [[]] |
[[ ]] |
an internal link with an empty target (renders invisible single space) |
![[]] |
plain text ![[]] |
![[ ]] |
the note embedded into itself |
![[ ]] behaves identically to writing an explicit self-embed: the embed nests
until the recursion guard stops it, measured at 6 levels for both
![[ ]] and ![[<this note>]], versus 1 level for a normal embed. There is no
hang or crash (the guard handles it correctly). The issue is only that a
whitespace-only target resolves to the current note in the first place.
Tabs behave the same as spaces, and extra spaces make no difference: [[ ]]
and [[<tab>]] both produce the empty-target link.
The rendered markup for the two whitespace forms:
<!-- [[ ]] -->
<a data-href="" href="" class="internal-link"></a>
<!-- ![[ ]] -->
<span alt="" src="" class="internal-embed markdown-embed inline-embed is-loaded">
<div class="embed-title markdown-embed-title">…name of the containing note…</div>
<div class="markdown-embed-content">…contents of the containing note…</div>
</span>
At the API level, metadataCache records these as resolved links pointing at the
containing note, so resolvedLinks["A.md"] contains {"A.md": 1} for a note
containing [[ ]]. I mention this as supporting evidence for the parse; it is not
visible in the Backlinks pane.
For contrast, these behave correctly:
| Source | Result |
|---|---|
[[]] |
plain text, no link |
![[]] |
plain text, no embed |
[[ target ]] |
link to target, correctly trimmed |
[[#h]] |
link to the current note’s h heading |
[[#h]] is documented as a legitimate current-note heading link. [[ ]] appears
to reach that same path once its whitespace target is trimmed to an empty string,
which would explain the self-reference.
Environment
SYSTEM INFO:
Obsidian version: 1.14.2
Installer version: 1.12.7
Operating system: #1-NixOS SMP PREEMPT_DYNAMIC Mon Sep 14 11:36:19 UTC 2026 6.18.52
Login status: logged in
Language: en
Catalyst license: vip
Insider build toggle: on
Live preview: on
Base theme: adapt to system
Community theme: none
Snippets enabled: 0
Restricted mode: on
RECOMMENDATIONS:
none
Distro Name: NixOS
Distro Version: Linux kernel 6.18.52
Desktop Environment: Wayland/Hyprland
Installation method used: Nix
Additional information
Also reproduces on app version 1.13.7, so this is not specific to 1.14.
Related existing reports — none describe the whitespace-only target, but they
establish that self-embedding needs care and that a depth guard exists:
- Export PDF causes infinite loop if there are recursive note embeds (v0.11.13)
- Make rendering limit of nested embedded notes adjustable
Measured incidentally while investigating: the nested-embed limit is 6 levels on
1.14.2, which may be useful for that second thread since it estimates roughly five.
Empty wikilinks have had dedicated handling before (the 0.13.1 changelog records
“Fixed empty wikilinks disappears”) which suggests the whitespace case is an
oversight rather than intended.
A possibly related case: [[ |alias]] and [[|alias]] do not treat the pipe as an
alias separator when the path is empty. The whole string becomes the target,
producing an unresolved link named |alias.
Found while building a differential-testing harness for
@quartz-community/remark-obsidian,
a remark plugin aiming for parity with Obsidian’s reading-mode output.