{"record":{"id":"e0e8eb0a44322bdc","repo":"d12frosted/homebrew-emacs-plus","slug":"invalid-build-yml-at-path-expected-a-yaml-mappi","errorCode":null,"errorMessage":"Invalid build.yml at #{path}\nExpected a YAML mapping (key: value pairs), but got: #{config.class}\nContent: #{config.inspect[0..100]}\n\nCommon causes:\n  - Missing space after colon (use 'icon: value' not 'icon:value')\n  - File contains only a string instead of key-value pairs","messagePattern":"Invalid build\\.yml at #(.+?)\nExpected a YAML mapping \\(key: value pairs\\), but got: #(.+?)\nContent: #(.+?)\n\nCommon causes:\n  - Missing space after colon \\(use 'icon: value' not 'icon:value'\\)\n  - File contains only a string instead of key-value pairs","errorType":"validation","errorClass":"ConfigurationError","httpStatus":null,"severity":"error","filePath":"Library/BuildConfig.rb","lineNumber":156,"sourceCode":"                                (expand-file-name (file-name-directory emutls))))\n                             \"#{prefix}/lib/gcc/current\"\n                             \"#{prefix}/opt/libgccjit/lib/gcc/current\"\n                             \"#{prefix}/lib\")))\n            (unless (boundp 'native-comp-driver-options)\n              (setq native-comp-driver-options nil))\n            (dolist (dir dirs)\n              (when dir\n                (let ((flag (concat \"-L\" dir)))\n                  (unless (member flag native-comp-driver-options)\n                    (setq native-comp-driver-options\n                          (append native-comp-driver-options (list flag)))))))))\n      ELISP\n    end\n\n    # Validate that config has the expected structure\n    def validate_config!(config, path)\n      unless config.is_a?(Hash)\n        raise ConfigurationError,\n          \"Invalid build.yml at #{path}\\n\" \\\n          \"Expected a YAML mapping (key: value pairs), but got: #{config.class}\\n\" \\\n          \"Content: #{config.inspect[0..100]}\\n\\n\" \\\n          \"Common causes:\\n\" \\\n          \"  - Missing space after colon (use 'icon: value' not 'icon:value')\\n\" \\\n          \"  - File contains only a string instead of key-value pairs\"\n      end\n\n      # Check for unknown keys\n      unknown_keys = config.keys - ALL_KEYS\n      unless unknown_keys.empty?\n        suggestions = unknown_keys.map { |k| suggest_key(k) }.compact\n        suggestion_text = suggestions.empty? ? \"\" : \"\\n\\nDid you mean:\\n#{suggestions.map { |s| \"  - #{s}\" }.join(\"\\n\")}\"\n\n        raise ConfigurationError,\n          \"Unknown configuration key(s) in #{path}: #{unknown_keys.join(', ')}\\n\" \\\n          \"Valid keys are: #{ALL_KEYS.join(', ')}#{suggestion_text}\"\n      end","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/d12frosted/homebrew-emacs-plus/blob/01c47fe98f35ff28a37a89e1f7aafadff621f9e0/Library/BuildConfig.rb#L138-L174","documentation":"The YAML parsed, but the whole document is not a mapping: validate_config! (Library/BuildConfig.rb:154-163) requires the top-level node to be a Hash of key: value pairs and reports the class it actually got (String, Array, Integer, NilClass, ...). The empty-file case is already short-circuited at line 67 (`return {} if content.strip.empty?`), so the NilClass variant almost always comes from a comments-only file - comments alone do not count as empty content to String#strip.","triggerScenarios":"A build.yml whose top-level parses to anything other than a Hash: the classic `icon:value` with no space after the colon (the whole line becomes one scalar String), a file containing only a bare scalar, a top-level list (`- icon: X`), a lone number/boolean, or a file holding only comments (safe_load returns nil, so the message says NilClass).","commonSituations":"Forgetting the space after the colon (YAML treats `icon:value` as a scalar string, not a pair); pasting a prose description or chat answer instead of actual config; commenting out every key while debugging and leaving a comments-only file; wrapping config in a top-level list because a website snippet was formatted that way.","solutions":["Make every top-level line a `key: value` pair with a space after the colon - start with `icon: Spacemacs` and re-run.","If you commented out all keys, empty the file completely (zero bytes) or delete it - a comments-only file still reaches the parser and yields nil.","Remove top-level `- item` list syntax; keys may not live under list items.","Verify locally: `ruby -ryaml -e 'p YAML.safe_load(File.read(ARGV[0]))' <file>` must print a Hash (nil is acceptable only for a truly empty file)."],"exampleFix":"# before - no space after colon; whole file parses to the String \"icon:Spacemacs\"\nicon:Spacemacs\n\n# after\nicon: Spacemacs","handlingStrategy":"validation","validationCode":"require \"yaml\"\ncontent = File.read(path)\nparsed = content.strip.empty? ? {} : YAML.safe_load(content, permitted_classes: [Symbol])\nabort \"#{path}: top level must be a key: value mapping, got #{parsed.class}\" unless parsed.is_a?(Hash)","typeGuard":"def build_yaml_mapping?(path)\n  content = File.read(path)\n  return true if content.strip.empty?\n  YAML.safe_load(content, permitted_classes: [Symbol]).is_a?(Hash)\nend","tryCatchPattern":"begin\n  BuildConfig.load_config\nrescue BuildConfig::ConfigurationError => e\n  abort e.message if e.message.include?(\"Expected a YAML mapping\")\n  raise\nend","preventionTips":["Always type a space after the colon - `key:value` is a scalar, `key: value` is a pair","Seed new configs from a known-good example that already has top-level keys","A comments-only file is NOT empty; truly empty or deleted means 'no config'","When commenting everything out to bisect a problem, leave one harmless valid key such as `inject_path: false`"],"tags":["yaml","configuration","type-mismatch","emacs-plus","homebrew"],"backgroundTag":"yaml-type-mismatch","analyzedSha":"01c47fe98f35ff28a37a89e1f7aafadff621f9e0","analyzedAt":"2026-08-23T16:25:45.065Z","schemaVersion":2},"datasetVersion":"2026-08-23T21:17:23.414Z"}