googleapis/mcp-toolbox · critical
tool type %q already registered
Error message
tool type %q already registered
What it means
This panic is thrown by init() in internal/tools/dataform/dataformcompilelocal because tools.Register for resourceType "dataform-compile-local" found the key already present in the tool registry and returned false. The library fails fast at startup rather than allowing one tool config factory to overwrite another. The remedy is a single, unique registration for this tool type per process.
Source
Thrown at internal/tools/dataform/dataformcompilelocal/dataformcompilelocal.go:34
import (
"context"
"fmt"
"os/exec"
"strings"
"github.com/goccy/go-yaml"
"github.com/googleapis/mcp-toolbox/internal/sources"
"github.com/googleapis/mcp-toolbox/internal/tools"
"github.com/googleapis/mcp-toolbox/internal/util"
"github.com/googleapis/mcp-toolbox/internal/util/parameters"
)
const resourceType string = "dataform-compile-local"
func init() {
if !tools.Register(resourceType, newConfig) {
panic(fmt.Sprintf("tool type %q already registered", resourceType))
}
}
func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (tools.ToolConfig, error) {
actual := Config{ConfigBase: tools.ConfigBase{Name: name}}
if err := decoder.DecodeContext(ctx, &actual); err != nil {
return nil, err
}
return actual, nil
}
type Config struct {
tools.ConfigBase `yaml:",inline"`
Type string `yaml:"type" validate:"required"`
Annotations *tools.ToolAnnotations `yaml:"annotations,omitempty"`
}
var _ tools.ToolConfig = Config{}View on GitHub (pinned to 8cc6e09de2)
Solutions
- Grep for "dataform-compile-local" and remove or rename the duplicate resourceType.
- Keep one source of truth for the tool type key in the dataformcompilelocal package.
- Run `go build ./...` and unit tests to confirm only one registration executes.
- Avoid calling tools.Register manually in tests for types registered by init().
Example fix
// before const resourceType string = "dataform-compile-local" // duplicate declaration elsewhere // after const resourceType string = "dataform-compile-local" // only in dataformcompilelocal.go; duplicate deleted
Defensive patterns
Strategy: validation
Validate before calling
const want = "dataform-compile-local" // before adding/renaming the tool, run: // git grep -n '"dataform-compile-local"' -- '*.go' // exactly one const declaration is required.
Try / catch
func mustRegister(key string, fn func(context.Context, string, *yaml.Decoder) (tools.ToolConfig, error)) {
defer func() {
if r := recover(); r != nil {
log.Fatalf("tool %s: %v", key, r)
}
}()
if !tools.Register(key, fn) {
log.Fatalf("tool %s already registered", key)
}
} Prevention
- Keep the resourceType const declared only in the tool's own file.
- Grep for the key before introducing a new or renamed tool.
- Never call tools.Register outside package init().
- Ensure go.mod/vendor contains a single copy of the module.
- Run unit tests that exercise all init() registrations in CI.
When it happens
Trigger: Another file/package declares the same "dataform-compile-local" const and its init() also registers it; or test/bootstrap code calls tools.Register again for the same key after package init already did.
Common situations: Renaming a tool package but keeping the old resourceType that already exists; merging two branches that both add dataform-compile-local; tests that exercise registration explicitly while init has already run.
Related errors
- tool type %q already registered
- tool type %q already registered
- tool type %q already registered
- tool type %q already registered
- tool type %q already registered
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/9b0082d0ff819514.
Report an issue: GitHub.