hashicorp/vagrant · error · Vagrant::Plugin::V2::InvalidCommandName
Commands can only contain letters, numbers, and hyphens
Error message
Commands can only contain letters, numbers, and hyphens
What it means
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.
Source
Thrown at lib/vagrant/plugin/v2/plugin.rb:93
# set, every middleware action is hooked.
# @return [Array] List of the hooks for the given action.
def self.action_hook(name, hook_name=nil, &block)
# The name is currently not used but we want it for the future.
hook_name = hook_name.to_s if hook_name
hook_name ||= ALL_ACTIONS
components.action_hooks[hook_name.to_sym] << block
end
# Defines additional command line commands available by key. The key
# becomes the subcommand, so if you register a command "foo" then
# "vagrant foo" becomes available.
#
# @param [String] name Subcommand key.
def self.command(name, **opts, &block)
# Validate the name of the command
if name.to_s !~ /^[-a-z0-9]+$/i
raise InvalidCommandName, "Commands can only contain letters, numbers, and hyphens"
end
# By default, the command is primary
opts[:primary] = true if !opts.key?(:primary)
# Register the command
components.commands.register(name.to_sym) do
[block, opts]
end
nil
end
# Defines additional communicators to be available. Communicators
# should be returned by a block passed to this method. This is done
# to ensure that the class is lazy loaded, so if your class inherits
# from or uses any Vagrant internals specific to Vagrant 1.0, then
# the plugin can still be defined without breaking anything in futureView on GitHub (pinned to 35f3160f4a)
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)
Example fix
# before
class MyPlugin < Vagrant.plugin("2")
name "my plugin"
command "my_command" do
require File.expand_path("../command", __FILE__)
Command
end
end
# after
class MyPlugin < Vagrant.plugin("2")
name "my plugin"
command "my-command" do
require File.expand_path("../command", __FILE__)
Command
end
end Defensive patterns
Strategy: type-guard
Validate before calling
COMMAND_NAME_RE = /\A[-a-zA-Z0-9]+\z/
raise "invalid command name '#{name}'" unless name.to_s.match?(COMMAND_NAME_RE) Type guard
# Ruby guard for the Vagrant v2 command DSL COMMAND_NAME_RE = /\A[-a-zA-Z0-9]+\z/ def valid_command_name?(name) name.is_a?(String) && !name.empty? && name.match?(COMMAND_NAME_RE) end
Try / catch
begin
command "my-command" do
require_relative "command"
Command
end
rescue Vagrant::Plugin::V2::Errors::InvalidCommandName => e
warn e.message # "Commands can only contain letters, numbers, and hyphens"
end Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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 `::`.
Related errors
- Commands can only contain letters, numbers, and hyphens
- There are errors in the configuration of this machine. Pleas
- There are errors in the configuration of this machine. Pleas
- An invalid option was specified. The help for this command i
- No virtual machines matched the regular expression given.
AI-assisted analysis of hashicorp/vagrant@35f3160f4a (2026-08-21).
Data as JSON: /api/errors/259bb0380311cd4d.
Report an issue: GitHub.