rust-lang/mdBook · error
redirect entry for `{original}` only has source paths with `
Error message
redirect entry for `{original}` only has source paths with `#` fragments
There must be an entry without the `#` fragment to determine the default destination. What it means
mdBook's HTML renderer emits a redirect file for each entry in output.html.redirect. If the redirect key (the source path) contains a '#' fragment, the key alone doesn't identify a file to redirect from, so at least one entry for the same path WITHOUT the '#' fragment must exist to define the default destination page. This error is raised in emit_redirects when only fragment-bearing entries exist for a path.
Source
Thrown at crates/mdbook-html/src/html_handlebars/hbs_renderer.rs:261
if redirects.is_empty() {
return Ok(());
}
debug!("Emitting redirects");
let redirects = combine_fragment_redirects(redirects);
for (original, (dest, fragment_map)) in redirects {
// Note: all paths are relative to the build directory, so the
// leading slash in an absolute path means nothing (and would mess
// up `root.join(original)`).
let original = original.trim_start_matches('/');
let filename = root.join(original);
if filename.exists() {
// This redirect is handled by the in-page fragment mapper.
continue;
}
if dest.is_empty() {
bail!(
"redirect entry for `{original}` only has source paths with `#` fragments\n\
There must be an entry without the `#` fragment to determine the default \
destination."
);
}
debug!("Redirecting \"{}\" → \"{}\"", original, dest);
self.emit_redirect(handlebars, &filename, &dest, &fragment_map)?;
}
Ok(())
}
fn emit_redirect(
&self,
handlebars: &Handlebars<'_>,
original: &Path,
destination: &str,
fragment_map: &BTreeMap<String, String>,View on GitHub (pinned to dc21064fc2)
Solutions
- Add a redirect entry without the '#' fragment for the same source path, e.g. "old.html" -> "new.html", alongside any fragment entries.
- If the bare source file exists on disk in the build output, remove it or let the in-page fragment mapper handle it (the check is skipped when filename.exists()).
- Remove the fragment-only redirect entries if they are no longer needed.
Example fix
// before (book.toml) [output.html.redirect] "old/page.html#section" = "new/page.html" // after [output.html.redirect] "old/page.html" = "new/page.html" "old/page.html#section" = "new/page.html#section"
Defensive patterns
Strategy: validation
Validate before calling
// Scan book.toml before building
for key in redirect_keys {
if key.contains('#') {
let bare = key.split('#').next().unwrap();
assert!(redirect_keys.contains(bare), "add a redirect for {bare} without a fragment");
}
} Prevention
- Always pair every fragment redirect with a bare-path redirect for the same file.
- Keep redirects minimal and review [output.html.redirect] after restructures.
When it happens
Trigger: output.html.redirect contains only keys like "path/to/page.html#section" for a given original path, with no bare key like "path/to/page.html", and the bare filename does not exist on disk (so it isn't handled by the in-page fragment mapper).
Common situations: Users add fragment redirects (e.g. "old.html#api" -> "new.html") but forget the entry mapping the page itself; renaming chapters while updating old fragment links; hand-editing book.toml redirects section.
Related errors
- redirect found for existing chapter at `{path}` Either delet
- theme dir {} does not exist
- [output.html.search.chapter] key `{}` does not match any cha
- unable to get `{name}`, only `output` and `preprocessor` tab
- invalid key `{index}`
AI-assisted analysis of rust-lang/mdBook@dc21064fc2 (2026-09-01).
Data as JSON: /api/errors/2166d0716e3bf2f6.
Report an issue: GitHub.