{"record":{"id":"259bb0380311cd4d","repo":"hashicorp/vagrant","slug":"commands-can-only-contain-letters-numbers-and-hy-259bb0","errorCode":null,"errorMessage":"Commands can only contain letters, numbers, and hyphens","messagePattern":"Commands can only contain letters, numbers, and hyphens","errorType":"exception","errorClass":"Vagrant::Plugin::V2::InvalidCommandName","httpStatus":null,"severity":"error","filePath":"lib/vagrant/plugin/v2/plugin.rb","lineNumber":93,"sourceCode":"        #   set, every middleware action is hooked.\n        # @return [Array] List of the hooks for the given action.\n        def self.action_hook(name, hook_name=nil, &block)\n          # The name is currently not used but we want it for the future.\n          hook_name = hook_name.to_s if hook_name\n\n          hook_name ||= ALL_ACTIONS\n          components.action_hooks[hook_name.to_sym] << block\n        end\n\n        # Defines additional command line commands available by key. The key\n        # becomes the subcommand, so if you register a command \"foo\" then\n        # \"vagrant foo\" becomes available.\n        #\n        # @param [String] name Subcommand key.\n        def self.command(name, **opts, &block)\n          # Validate the name of the command\n          if name.to_s !~ /^[-a-z0-9]+$/i\n            raise InvalidCommandName, \"Commands can only contain letters, numbers, and hyphens\"\n          end\n\n          # By default, the command is primary\n          opts[:primary] = true if !opts.key?(:primary)\n\n          # Register the command\n          components.commands.register(name.to_sym) do\n            [block, opts]\n          end\n\n          nil\n        end\n\n        # Defines additional communicators to be available. Communicators\n        # should be returned by a block passed to this method. This is done\n        # to ensure that the class is lazy loaded, so if your class inherits\n        # from or uses any Vagrant internals specific to Vagrant 1.0, then\n        # the plugin can still be defined without breaking anything in future","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/hashicorp/vagrant/blob/35f3160f4ad6edc3a9f3aa9570adfc1a4d73aaa5/lib/vagrant/plugin/v2/plugin.rb#L75-L111","documentation":"Plugin DSL validation in the v2 API: the name passed to `command(name, **opts)` must match /^[-a-z0-9]+$/i — letters, digits, and hyphens only (lib/vagrant/plugin/v2/plugin.rb:93). Anything else (underscores, colons, spaces) raises Vagrant::Plugin::V2::Errors::InvalidCommandName while the plugin is being defined, before the command is registered or can run.","triggerScenarios":"A plugin's `class MyPlugin < Vagrant.plugin(\"2\")` block calling `command \"my_command\"` or `command \"ns:cmd\"` — components.commands.register is never reached because the name check fails first.","commonSituations":"Plugin authors carrying Ruby underscore naming or rake-style colon namespacing into subcommand keys; automated code generation that derives the command key from a class name containing `::`.","solutions":["Rename the subcommand to hyphenated lowercase: my_command -> my-command","Only the subcommand key is validated — the gem/plugin display name can stay as-is","Use hyphenated prefixes for grouping (myplug-list, myplug-add)"],"exampleFix":"# before\nclass MyPlugin < Vagrant.plugin(\"2\")\n  name \"my plugin\"\n  command \"my_command\" do\n    require File.expand_path(\"../command\", __FILE__)\n    Command\n  end\nend\n\n# after\nclass MyPlugin < Vagrant.plugin(\"2\")\n  name \"my plugin\"\n  command \"my-command\" do\n    require File.expand_path(\"../command\", __FILE__)\n    Command\n  end\nend","handlingStrategy":"type-guard","validationCode":"COMMAND_NAME_RE = /\\A[-a-zA-Z0-9]+\\z/\nraise \"invalid command name '#{name}'\" unless name.to_s.match?(COMMAND_NAME_RE)","typeGuard":"# Ruby guard for the Vagrant v2 command DSL\nCOMMAND_NAME_RE = /\\A[-a-zA-Z0-9]+\\z/\ndef valid_command_name?(name)\n  name.is_a?(String) && !name.empty? && name.match?(COMMAND_NAME_RE)\nend","tryCatchPattern":"begin\n  command \"my-command\" do\n    require_relative \"command\"\n    Command\n  end\nrescue Vagrant::Plugin::V2::Errors::InvalidCommandName => e\n  warn e.message # \"Commands can only contain letters, numbers, and hyphens\"\nend","preventionTips":["Use hyphens only in subcommand keys — never underscores or colons","Exercise plugin registration in the plugin's spec suite to catch name errors at load","Keep DSL names constant even when internal class names use underscores"],"tags":["plugin-development","validation","naming","v2-plugins"],"backgroundTag":"invalid-identifier","analyzedSha":"35f3160f4ad6edc3a9f3aa9570adfc1a4d73aaa5","analyzedAt":"2026-08-21T13:34:32.514Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}