googleapis/mcp-toolbox · error
tool type %q already registered
Error message
tool type %q already registered
What it means
This panic comes from the package-level init() of the postgres-list-views tool package. The tools.Register() call maintains a global map of tool type strings to config constructors and returns false if the key already exists, i.e. "postgres-list-views" was registered twice. Since registration happens in init(), the panic aborts the binary at startup.
Source
Thrown at internal/tools/postgres/postgreslistviews/postgreslistviews.go:55
viewowner AS owner_name,
definition
FROM pg_views
)
SELECT *
FROM list_views
WHERE
schema_name NOT IN ('pg_catalog', 'information_schema', 'pg_toast')
AND schema_name NOT LIKE 'pg_temp_%'
AND ($1::text IS NULL OR view_name ILIKE '%' || $1::text || '%')
AND ($2::text IS NULL OR schema_name ILIKE '%' || $2::text || '%')
ORDER BY
schema_name, view_name
LIMIT COALESCE($3::int, 50);
`
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 compatibleSource interface {
PostgresPool() *pgxpool.Pool
RunSQL(context.Context, string, []any) (any, error)
}
type Config struct {
tools.ConfigBase `yaml:",inline"`View on GitHub (pinned to 8cc6e09de2)
Solutions
- Grep for "postgres-list-views" to find every registration and delete/rename the duplicate.
- Give a copied package a unique kebab-case resourceType.
- Remove duplicate import paths / vendor copies and rebuild.
- Check git diff for accidental duplicate init() or constant edits before building.
Example fix
// before const resourceType string = "postgres-list-views" // registered twice // after // stock package keeps "postgres-list-views"; // new package: const resourceType string = "postgres-list-materialized-views"
Defensive patterns
Strategy: validation
Validate before calling
// Startup validation in main() (for forks that control registration):
key := "postgres-list-views"
if _, exists := registeredKeys[key]; exists {
return fmt.Errorf("refusing to start: %q registered twice", key)
} Type guard
func isDuplicate(key string, seen map[string]bool) bool {
if seen[key] { return true }
seen[key] = true
return false
} Try / catch
defer func() {
if r := recover(); r != nil {
log.Fatalf("tool registration panic (duplicate resourceType?): %v", r)
}
}() // wrap the code path that first imports tool packages Prevention
- Use a naming convention (postgres-<entity>-<action>) and check it before adding a new key.
- Add a lint/test that asserts unique resourceType constants across internal/tools.
- Avoid vendor/fork duplication of postgres tool packages.
- Review merge conflicts in tool packages for leftover duplicate init() blocks.
When it happens
Trigger: A build containing two registrations for "postgres-list-views": a duplicated postgreslistviews package under a different import path (vendor/fork), or a modified resourceType in another postgres tool package colliding with postgres-list-views (postgreslistviews.go:30).
Common situations: Template-copying postgreslistviews.go to create a new listing tool without changing resourceType; duplicate vendoring; merge conflict residue; custom prebuilt configs compiled into a binary that also links the stock package under a second path.
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/a7b4a8e4c4666db0.
Report an issue: GitHub.