Skip to content

Markdown-style links to notes are never resolved: full reload, then a dead end #293

Description

@BattermanZ

Found while routing in-body note links through the router. That change fixed the full page reload for wikilinks, which are the only note links Hatchdoor resolves. A note link written the plain-Markdown way is a different problem: it has never worked, and it does not merely reload, it lands nowhere.

What happens

A link like [Beacon Launch](Beacon%20Launch.md) renders as a link, is clickable, and goes to a dead end. The href is left exactly as the author wrote it, so the browser resolves it against the current note's URL.

Measured in Chromium against just dev-start, from a note in 00-inbox linking to 20-projects/Beacon Launch.md:

written in the note href in the page where the click lands what the reader sees
[[Beacon Launch]] /v/<id>/n/beacon-launch the note works, router navigation
[x](Beacon%20Launch.md) Beacon%20Launch.md /v/<id>/n/Beacon%20Launch.md full page reload, then "Note not found: Beacon Launch.md"
[x](20-projects/Beacon%20Launch.md) 20-projects/Beacon%20Launch.md /v/<id>/n/20-projects/Beacon%20Launch.md full page reload, then a blank pane: no route matches, so nothing renders and no error is shown
[x](../20-projects/Beacon%20Launch.md) ../20-projects/Beacon%20Launch.md /v/<id>/20-projects/Beacon%20Launch.md same blank pane

The blank-pane cases are the worse ones. The sidebar is there, the main pane is empty, and nothing says why.

These links are also invisible to backlinks, the Links panel, the graph and statistics, so a vault using them looks unlinked even where it is densely cross-referenced.

Note that a target with a raw space, [x](Beacon Launch.md), is not a link at all under CommonMark and renders as literal text. Only the percent-encoded form reaches this path, which is the form Obsidian writes.

Cause

Two places understand [[ ]] and nothing else.

extract_wikilink_targets in src/vault/links.rs:82 scans each non-code line for [[ and collects what follows. It feeds outgoing links and backlinks, and through them the Links panel, the graph and the link statistics. A Markdown link contributes nothing to any of them.

rewriteWikilinks in frontend/src/components/note-page/wikilinks.ts:50 matches /(!?)\[\[([^\]\r\n]+)\]\]/g and rewrites a resolved hit into /v/<vault>/n/<slug>. A Markdown target is never sent to resolve-batch and never rewritten.

By the time the href reaches the markdown renderer's a component in frontend/src/components/note-page/renderers.tsx, it is a relative filename. It is not a sentinel, not external, not a PDF and not a note route, so it falls to the plain anchor branch and the browser takes it from there.

Who hits this

Obsidian's Files and links settings carry a Use [[Wikilinks]] toggle. With it switched off, Obsidian writes every new link in the Markdown form with a percent-encoded path. A vault authored that way has no working note links in Hatchdoor at all, and no backlinks either, while looking completely normal in Obsidian.

Suggested direction

The resolver already knows how to answer this. normalize_link_target in src/vault/paths.rs:29 strips a .md suffix and normalises separators, and resolve_target_slug matches a target by path-title or by basename. A Markdown target is exactly the shape those two already accept. The missing step is recognising it as a note reference in the first place.

Two decisions to take before writing anything:

How far the fix goes. Rewriting the href in wikilinks.ts makes the links navigate and is frontend-only. Teaching extract_wikilink_targets about the Markdown form as well makes them count as links, which is more correct but changes backlinks, the graph and the statistics for every existing vault, and needs a decision about whether that shift is wanted.

What an unresolved or non-note target does. A wikilink that resolves to nothing renders as a broken-link span rather than a link. A Markdown target that names no note should presumably do the same, but that means deciding what "names no note" is for a target that could equally be an attachment. Related: the .pdf branch already rewrites a relative PDF target to the asset endpoint, while other attachment extensions, .mp4 among them, fall through to the same bare anchor and the same dead URL. Worth settling both in one pass, since it is one classifier.

Scope

Navigation only: frontend/src/components/note-page/wikilinks.ts, frontend/src/components/note-page/renderers.tsx, and their tests.

Including link records: src/vault/links.rs and its resolver, plus whatever the note-links contract change pulls in. That path needs the interface-change checklist and probably an ADR, since backlinks are a supported contract and existing vaults would see their link counts move.

Priority note

Low, with a caveat. Nothing regressed, this has never worked, and a vault authored with wikilinks throughout never produces the shape. But it is silent: the links look right, the blank-pane variant reports nothing, and someone arriving from an Obsidian vault with wikilinks turned off would find every link in their vault broken with no message explaining it. That makes it worth a decision even if the fix waits.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestneeds-triageAwaiting maintainer evaluation

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions