golang/go · error
bad tool name: %q
Error message
bad tool name: %q
What it means
Returned by base.ToolPath(toolName) when ValidToolName(toolName) is false. The go command builds the expected binary path as filepath.Join(build.ToolDir, toolName)+ToolExeSuffix, so a malformed tool name would produce a nonsense path; validation rejects it up front. An empty string or any character outside the accepted set trips the guard.
Source
Thrown at src/cmd/go/internal/base/tool.go:34
// Tool returns the path to the named builtin tool (for example, "vet").
// If the tool cannot be found, Tool exits the process.
func Tool(toolName string) string {
toolPath, err := ToolPath(toolName)
if err != nil && len(cfg.BuildToolexec) == 0 {
// Give a nice message if there is no tool with that name.
fmt.Fprintf(os.Stderr, "go: no such tool %q\n", toolName)
SetExitStatus(2)
Exit()
}
return toolPath
}
// ToolPath returns the path at which we expect to find the named tool
// (for example, "vet"), and the error (if any) from statting that path.
func ToolPath(toolName string) (string, error) {
if !ValidToolName(toolName) {
return "", fmt.Errorf("bad tool name: %q", toolName)
}
toolPath := filepath.Join(build.ToolDir, toolName) + cfg.ToolExeSuffix()
err := toolStatCache.Do(toolPath, func() error {
_, err := os.Stat(toolPath)
return err
})
return toolPath, err
}
func ValidToolName(toolName string) bool {
if toolName == "" {
return false
}
for _, c := range toolName {
switch {
case 'a' <= c && c <= 'z', '0' <= c && c <= '9', c == '_':
default:
return falseView on GitHub (pinned to b6b368adc5)
Solutions
- Validate with base.ValidToolName(name) before calling ToolPath.
- Use the known tool-name constants (e.g. "vet", "build") rather than constructing names from input.
- Trim and reject empty strings at the call site.
- If the name originates from argv/config, sanitize to alphanumeric+underscore before forwarding.
Example fix
// before
p, err := base.ToolPath(name) // panics-style error when name=""
// after
if !base.ValidToolName(name) {
return fmt.Errorf("invalid tool name %q", name)
}
p, err := base.ToolPath(name) Defensive patterns
Strategy: validation
Validate before calling
if !base.ValidToolName(name) {
return fmt.Errorf("rejecting invalid tool name %q", name)
}
path, err := base.ToolPath(name) Type guard
func isValidToolName(s string) bool {
if s == "" { return false }
for _, r := range s {
if r == '/' || r == '\\' || r == ' ' || unicode.IsControl(r) {
return false
}
}
return true
} Prevention
- Never build tool names from raw user input without sanitizing.
- Prefer named constants ("vet", "build") over dynamic strings.
- Unit-test the empty-string and separator cases at the call site.
When it happens
Trigger: Calling base.ToolPath("") or with a name containing path separators, spaces, or characters not allowed by ValidToolName (which rejects empty and non-simple names).
Common situations: Code that builds tool names dynamically from user/file input; off-by-one slicing producing an empty string; passing a path instead of a bare tool name.
Related errors
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/5df4aeadfc74f2b9.
Report an issue: GitHub.