{"record":{"id":"216ea787dad6bf91","repo":"d12frosted/homebrew-emacs-plus","slug":"invalid-key-version-map-in-path-version-ke","errorCode":null,"errorMessage":"Invalid '#{key}' version map in #{path}\nVersion keys must be major Emacs versions (e.g. \"30\") or 'default'.\nGot key(s): #{bad.map(&:inspect).join(', ')}","messagePattern":"Invalid '#(.+?)' version map in #(.+?)\nVersion keys must be major Emacs versions \\(e\\.g\\. \"30\"\\) or 'default'\\.\nGot key\\(s\\): #(.+?)","errorType":"validation","errorClass":"ConfigurationError","httpStatus":null,"severity":"error","filePath":"Library/BuildConfig.rb","lineNumber":255,"sourceCode":"          raise ConfigurationError,\n            \"Invalid '#{key}' configuration in #{path}\\n\" \\\n            \"When specifying an external icon, both 'url' and 'sha256' are required.\\n\" \\\n            \"Got: #{icon.inspect}\"\n        end\n      else\n        raise ConfigurationError,\n          \"Invalid '#{key}' in #{path}\\n\" \\\n          \"Expected: string (icon name) or object with 'url' and 'sha256'\\n\" \\\n          \"Got: #{icon.inspect} (#{icon.class})\"\n      end\n    end\n\n    # Validate that all keys of a version map are major versions or \"default\"\n    def validate_version_map_keys!(map, key, path)\n      bad = map.keys.reject { |k| k.to_s == \"default\" || k.to_s.match?(VERSION_KEY) }\n      return if bad.empty?\n\n      raise ConfigurationError,\n        \"Invalid '#{key}' version map in #{path}\\n\" \\\n        \"Version keys must be major Emacs versions (e.g. \\\"30\\\") or 'default'.\\n\" \\\n        \"Got key(s): #{bad.map(&:inspect).join(', ')}\"\n    end\n\n    def validate_inject_path!(value, path)\n      return if [true, false].include?(value)\n\n      raise ConfigurationError,\n        \"Invalid 'inject_path' in #{path}\\n\" \\\n        \"Expected: true or false\\n\" \\\n        \"Got: #{value.inspect} (#{value.class})\"\n    end\n\n    def validate_patches!(patches, path)\n      unless patches.is_a?(Array)\n        raise ConfigurationError,\n          \"Invalid 'patches' in #{path}\\n\" \\","sourceCodeStart":237,"sourceCodeEnd":273,"githubUrl":"https://github.com/d12frosted/homebrew-emacs-plus/blob/01c47fe98f35ff28a37a89e1f7aafadff621f9e0/Library/BuildConfig.rb#L237-L273","documentation":"A version map (used for `icon`, named `patches` entries, and `revision`) contains keys that are neither 'default' nor digit-only strings - i.e. not major Emacs versions. validate_version_map_keys! (Library/BuildConfig.rb:251-259) stringifies each key (`k.to_s`), so unquoted integer keys like `30:` pass and quoted \"30\" passes, but `\"30.1\"`, `\"29.4\"`, word keys (`mac:`), or YAML booleans (`true:` becomes TrueClass, to_s 'true') all fail and are listed with inspect in the message.","triggerScenarios":"`revision:` with minor-version keys (`\"29.4\":`); `icon:` with a word key (`mac:`, `dev:`); YAML 1.1 boolean keys (`on:`, `yes:`, `true:`); or a named patches entry carrying a version map keyed by a minor version like `\"29.2\"`.","commonSituations":"Pinning to an exact minor release (29.4, 30.1) without realizing version maps key on MAJOR Emacs versions only; using branch or channel names as keys; unquoted `on:`/`no:` keys silently becoming booleans; following examples written before the version-map feature settled.","solutions":["Use major versions only: \"29\" instead of \"29.4\", \"30\" instead of \"30.1\" - the build selects the entry by the major version of the Emacs being installed.","Use `default:` as the fallback bucket for everything you do not pin explicitly.","Rename word keys (branch/channel names) to a major version or to default.","If you need an exact point release, put the precise git commit hash under the major bucket - for `revision:` the value is a hex hash validated by validate_revision! anyway."],"exampleFix":"# before - minor version as key\nrevision:\n  \"29.4\": a1b2c3d4e5f6a7b8\n\n# after - major version key\nrevision:\n  \"29\": a1b2c3d4e5f6a7b8","handlingStrategy":"validation","validationCode":"def version_keys_ok?(map)\n  map.keys.all? { |k| k.to_s == \"default\" || k.to_s.match?(/\\A\\d+\\z/) }\nend\n\n%w[icon revision].each do |key|\n  v = config_hash[key]\n  next unless v.is_a?(Hash) && !(v.keys.map(&:to_s) - %w[url sha256]).empty?\n  abort \"#{key}: keys must be major Emacs versions or 'default'\" unless version_keys_ok?(v)\nend","typeGuard":"def version_map_keys_valid?(map)\n  map.keys.all? { |k| k.to_s == \"default\" || k.to_s.match?(/\\A\\d+\\z/) }\nend","tryCatchPattern":"begin\n  BuildConfig.load_config\nrescue BuildConfig::ConfigurationError => e\n  if e.message.include?(\"Version keys must be major Emacs versions\")\n    abort \"Change keys to major versions (\\\"30\\\") or 'default' - offending keys are listed in the error\"\n  end\n  raise\nend","preventionTips":["Version maps key on MAJOR Emacs versions only - never x.y minors","Quote numeric keys (\"30\") for clarity; bare integers work but strings document intent","Spell the fallback bucket exactly as 'default'","Beware YAML 1.1 booleans: unquoted on/yes/true keys become TrueClass and fail the digit check"],"tags":["configuration","version-map","emacs-version","validation","emacs-plus"],"backgroundTag":"invalid-version-key","analyzedSha":"01c47fe98f35ff28a37a89e1f7aafadff621f9e0","analyzedAt":"2026-08-23T16:25:45.065Z","schemaVersion":2},"datasetVersion":"2026-08-23T21:17:23.414Z"}