{"record":{"id":"e00b666f3485fae4","repo":"lsd-rs/lsd","slug":"failed-to-read-both-config-file-and-default-config","errorCode":null,"errorMessage":"Failed to read both config file and default config","messagePattern":"Failed to read both config file and default config","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/config_file.rs","lineNumber":212,"sourceCode":"impl Default for Config {\n    /// Try to find either config.yaml or config.yml in the config directories\n    /// and use the first one that is found. If none are found, or the parsing fails,\n    /// use the default from DEFAULT_CONFIG.\n    fn default() -> Self {\n        Config::config_paths()\n            .find_map(|p| {\n                let yaml = p.join(\"config.yaml\");\n                let yml = p.join(\"config.yml\");\n                if yaml.is_file() {\n                    Config::from_file(yaml)\n                } else if yml.is_file() {\n                    Config::from_file(yml)\n                } else {\n                    None\n                }\n            })\n            .or(Self::from_yaml(DEFAULT_CONFIG).ok())\n            .expect(\"Failed to read both config file and default config\")\n    }\n}\n\npub const DEFAULT_CONFIG: &str = r#\"---\n# == Classic ==\n# This is a shorthand to override some of the options to be backwards compatible\n# with `ls`. It affects the \"color\"->\"when\", \"sorting\"->\"dir-grouping\", \"date\"\n# and \"icons\"->\"when\" options.\n# Possible values: false, true\nclassic: false\n\n# == Blocks ==\n# This specifies the columns and their order when using the long and the tree\n# layout.\n# Possible values: permission, user, group, context, size, date, name, inode, links, git\nblocks:\n  - permission\n  - user","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/lsd-rs/lsd/blob/4b6c14a110fe0fd544ec0204501b5fd3a5d6218f/src/config_file.rs#L194-L230","documentation":"Config::default() tries the user config file (from_file on the located config path), then falls back to the compiled-in DEFAULT_CONFIG YAML, and finally .expect()s that at least one succeeded. This panic fires only when both the user's config file fails to parse AND the built-in default config fails to parse — which in practice means the embedded DEFAULT_CONFIG string is malformed (a build/embedding bug), not something a normal user causes.","triggerScenarios":"Calling Config::default() (via eza startup without --ignore-config) when from_file returns None (missing/unreadable config or parse error) and from_yaml(DEFAULT_CONFIG) returns Err because the embedded YAML does not deserialize into Config.","commonSituations":"A code change or merge corrupted the DEFAULT_CONFIG constant (note the double '---' document separator in the source, an easy YAML mistake); a serde rename/type change made the embedded defaults no longer deserialize; a user config with syntax errors combined with such a regression.","solutions":["Inspect and fix the DEFAULT_CONFIG constant in src/config_file.rs so it is valid YAML that deserializes into Config (watch duplicate '---' document separators).","Reproduce from_yaml(DEFAULT_CONFIG) in a test to see the serde error and fix the struct/field mismatches.","If a user config file is at fault, fix or remove it (default config locations such as ~/.config/eza/config.yml) or run with --ignore-config.","Upgrade/rebuild eza if running a distro build with a broken embedded default."],"exampleFix":"// before\npub const DEFAULT_CONFIG: &str = r#\"---\n# == Classic ==\n---\n...\"#; // stray second '---' can split/invalid documents\n// after\npub const DEFAULT_CONFIG: &str = r#\"# == Classic ==\n...\"#;","handlingStrategy":"fallback","validationCode":"// sanity-check embedded defaults before release\nlet cfg: Config = serde_yaml::from_str(DEFAULT_CONFIG)\n    .expect(\"DEFAULT_CONFIG must parse\");","typeGuard":"fn valid_user_config(s: &str) -> bool {\n    serde_yaml::from_str::<Config>(s).is_ok()\n}","tryCatchPattern":"let config = Config::default(); // panics by design\n// wrap at process boundary:\nlet result = std::panic::catch_unwind(|| Config::default());\nlet config = result.unwrap_or_else(|_| Config::with_none());","preventionTips":["Add a unit test that deserializes DEFAULT_CONFIG on every build.","Keep one YAML document (avoid stray '---' separators) in the embedded default.","Run eza with --ignore-config when debugging a broken user config.","After upgrading, diff your config keys against the new version's documented format."],"tags":["config","panic","yaml","deserialization"],"backgroundTag":"config-parse-failed","analyzedSha":"4b6c14a110fe0fd544ec0204501b5fd3a5d6218f","analyzedAt":"2026-09-04T20:04:26.847Z","contentChangedAt":"2026-09-04T20:04:26.847Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}