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

  1. Use Config::book, Config::build, Config::rust, or Config::get_table for non-output/preprocessor settings
  2. Prefix the key with "output." or "preprocessor." if that is what you intended
  3. 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

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


AI-assisted analysis of rust-lang/mdBook@dc21064fc2 (2026-09-01). Data as JSON: /api/errors/4d6d607a1d42a05b. Report an issue: GitHub.