rust-lang/mdBook · error
unable to get `{name}`, only `output` and `preprocessor` tab
Error message
unable to get `{name}`, only `output` and `preprocessor` table entries are allowed What it means
Config::get() only supports reading namespaced entries from the `output.*` or `preprocessor.*` tables of book.toml. Any other key (e.g. `build.` or `rust.` settings) is rejected with this error. It exists to keep the generic get() API scoped to plugin/output configuration surfaces.
Source
Thrown at crates/mdbook-core/src/config.rs:195
/// Get a value from the configuration.
///
/// This fetches a value from the book configuration. The key can have
/// dotted indices to access nested items (e.g. `output.html.playground`
/// will fetch the "playground" out of the html output table).
///
/// This can only access the `output` and `preprocessor` tables.
///
/// Returns `Ok(None)` if the field is not set.
///
/// Returns `Err` if it fails to deserialize.
pub fn get<'de, T: Deserialize<'de>>(&self, name: &str) -> Result<Option<T>> {
let (key, table) = if let Some(key) = name.strip_prefix("output.") {
(key, &self.output)
} else if let Some(key) = name.strip_prefix("preprocessor.") {
(key, &self.preprocessor)
} else {
bail!(
"unable to get `{name}`, only `output` and `preprocessor` table entries are allowed"
);
};
table
.read(key)
.map(|value| {
value
.clone()
.try_into()
.with_context(|| format!("Failed to deserialize `{name}`"))
})
.transpose()
}
/// Returns whether the config contains the given dotted key name.
///
/// The key can have dotted indices to access nested items (e.g.
/// `preprocessor.foo.bar` will check if that key is set in the config).View on GitHub (pinned to dc21064fc2)
Solutions
- Use Config::book, Config::build, Config::rust, or Config::get_table for non-output/preprocessor settings
- Prefix the key with "output." or "preprocessor." if that is what you intended
- Read the raw table via deserialize the whole config instead of get() for other sections
Example fix
// before
let dir: Option<String> = config.get("build.build-dir")?;
// after
let dir = config.build.build_dir().to_string_lossy().to_string(); Defensive patterns
Strategy: validation
Validate before calling
fn gettable(name: &str) -> bool {
name.starts_with("output.") || name.starts_with("preprocessor.")
} Type guard
fn is_namespaced_key(name: &str) -> bool {
name.starts_with("output.") || name.starts_with("preprocessor.")
} Try / catch
match config.get::<Value>(key) {
Ok(v) => /* use v */,
Err(e) if e.to_string().contains("only `output` and `preprocessor`") =>
/* read from config.book / config.build instead */,
Err(e) => return Err(e),
} Prevention
- Only call Config::get() for output.* and preprocessor.* keys
- Use the typed accessors (config.book, config.build, config.rust) for other sections
- Include the dot in the prefix — bare "output" is invalid
When it happens
Trigger: Calling config.get::<T>("build.dir") or any key that does not start with "output." or "preprocessor." (note: the exact prefix "output." / "preprocessor.", so "output" or "preprocessors" also fail).
Common situations: Plugin or custom renderer code trying to read general config like [build] or [book] via get(); typos in the prefix such as "outputs.html" or a missing dot.
Related errors
- invalid key `{index}`
- invalid key `{name}`
- failed to get `{key}`: {e}
- expected bool for `{optional_key}`: {e}
- redirect entry for `{original}` only has source paths with `
AI-assisted analysis of rust-lang/mdBook@dc21064fc2 (2026-09-01).
Data as JSON: /api/errors/4d6d607a1d42a05b.
Report an issue: GitHub.