{"record":{"id":"cf3eef49aa7aa25a","repo":"rust-lang/mdBook","slug":"invalid-key-index","errorCode":null,"errorMessage":"invalid key `{index}`","messagePattern":"invalid key `(.+?)`","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/mdbook-core/src/config.rs","lineNumber":301,"sourceCode":"            self.build = value.try_into()?;\n        } else if index == \"rust\" {\n            self.rust = value.try_into()?;\n        } else if index == \"output\" {\n            self.output = value;\n        } else if index == \"preprocessor\" {\n            self.preprocessor = value;\n        } else if let Some(key) = index.strip_prefix(\"book.\") {\n            self.book.update_value(key, value)?;\n        } else if let Some(key) = index.strip_prefix(\"build.\") {\n            self.build.update_value(key, value)?;\n        } else if let Some(key) = index.strip_prefix(\"rust.\") {\n            self.rust.update_value(key, value)?;\n        } else if let Some(key) = index.strip_prefix(\"output.\") {\n            self.output.update_value(key, value)?;\n        } else if let Some(key) = index.strip_prefix(\"preprocessor.\") {\n            self.preprocessor.update_value(key, value)?;\n        } else {\n            bail!(\"invalid key `{index}`\");\n        }\n\n        Ok(())\n    }\n}\n\nfn parse_env(key: &str) -> Option<String> {\n    key.strip_prefix(\"MDBOOK_\")\n        .map(|key| key.to_lowercase().replace(\"__\", \".\").replace('_', \"-\"))\n}\n\n/// Configuration options which are specific to the book and required for\n/// loading it from disk.\n#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]\n#[serde(default, rename_all = \"kebab-case\", deny_unknown_fields)]\n#[non_exhaustive]\npub struct BookConfig {\n    /// The book's title.","sourceCodeStart":283,"sourceCodeEnd":319,"githubUrl":"https://github.com/rust-lang/mdBook/blob/dc21064fc21d955a0e1f67e65e336883c3e5260b/crates/mdbook-core/src/config.rs#L283-L319","documentation":"Config::set() only accepts keys whose index begins with \"output.\" or \"preprocessor.\" (plus special-cased root/rust keys handled earlier in the function). Setting any other top-level value is rejected to avoid corrupting nested config tables via dotted-string mutation.","triggerScenarios":"Calling config.set(\"build.build-dir\", value) or any non-output/preprocessor dotted key; env-driven updates (update_from_env) with MDBOOK_<SECTION>__<KEY> variables whose section is not output/preprocessor/rust.","commonSituations":"Programmatic config editing scripts and MDBOOK_* environment variable overrides for sections like MDBOOK_BOOK__AUTHORS (note case: env keys are lowercased; unsupported sections hit this).","solutions":["Mutate the typed structs directly (config.book.title = ..., config.build) instead of set()","Only use set() for output.* / preprocessor.* values","For env overrides, use a supported section (build, rust, output, preprocessor) in the MDBOOK_ variable name"],"exampleFix":"// before\nconfig.set(\"book.title\", \"My Book\")?;\n// after\nconfig.book.title = Some(\"My Book\".to_string());","handlingStrategy":"validation","validationCode":"fn settable(key: &str) -> bool {\n    key.starts_with(\"output.\") || key.starts_with(\"preprocessor.\")\n}","typeGuard":"fn is_settable_index(index: &str) -> bool {\n    index.starts_with(\"output.\") || index.starts_with(\"preprocessor.\")\n}","tryCatchPattern":"if let Err(e) = config.set(key, value) {\n    if e.to_string().starts_with(\"invalid key\") {\n        // mutate typed fields directly instead\n    } else { return Err(e); }\n}","preventionTips":["Use set() only for output.*/preprocessor.* values","Prefer mutating config.book/config.build/config.rust fields directly","Check MDBOOK_ env var section names (build, rust, output, preprocessor) when using env overrides"],"tags":["config","api-misuse"],"backgroundTag":"invalid-config-key","analyzedSha":"dc21064fc21d955a0e1f67e65e336883c3e5260b","analyzedAt":"2026-09-01T10:15:12.134Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}