googleapis/mcp-toolbox · critical

tool type %q already registered

Error message

tool type %q already registered

What it means

This panic is raised by init() in internal/tools/databaseinsights/getadvancedtimeserieswaiteventstats because tools.Register was called with the resourceType "databaseinsights-get-advanced-time-series-wait-event-stats", which the registry already contains. tools.Register returns false on duplicate keys and the package panics to fail fast. It protects the invariant that each tool type maps to exactly one Config factory.

Source

Thrown at internal/tools/databaseinsights/getadvancedtimeserieswaiteventstats/getadvancedtimeserieswaiteventstats.go:34

import (
	"context"
	"fmt"
	"net/http"

	yaml "github.com/goccy/go-yaml"
	"github.com/googleapis/mcp-toolbox/internal/sources"
	"github.com/googleapis/mcp-toolbox/internal/sources/databaseinsights"
	"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 = "databaseinsights-get-advanced-time-series-wait-event-stats"

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 {
	FetchWaitEventTimeSeries(ctx context.Context, req *databaseinsights.FetchWaitEventTimeSeriesRequest) (*databaseinsights.FetchWaitEventTimeSeriesResponse, error)
}

type Config struct {
	tools.ConfigBase `yaml:",inline"`
	Type             string                 `yaml:"type" validate:"required"`

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Grep for "databaseinsights-get-advanced-time-series-wait-event-stats" and remove/rename the duplicate resourceType.
  2. Ensure the const is unique per tool package (kebab-case, source-prefixed).
  3. Check go.mod/vendor for duplicate copies of the module that would double-link the package.
  4. In test code, avoid re-registering types already registered by init().

Example fix

// before
const resourceType string = "databaseinsights-get-advanced-time-series-wait-event-stats" // conflicts with existing key
// after
const resourceType string = "databaseinsights-get-advanced-wait-event-timeseries" // renamed unique key
Defensive patterns

Strategy: validation

Validate before calling

const want = "databaseinsights-get-advanced-time-series-wait-event-stats"
// Run before adding the tool:
//   git grep -n 'databaseinsights-get-advanced-time-series-wait-event-stats' -- '*.go'
// More than one `const resourceType` hit means the registration will panic.

Try / catch

func safeRegister() (recovered any) {
    defer func() { recovered = recover() }()
    tools.Register(resourceType, newConfig)
    return nil
}
// at startup: if r := safeRegister(); r != nil { log.Fatalf("registry conflict: %v", r) }

Prevention

When it happens

Trigger: Two init() paths register the same resourceType constant (duplicate declaration in another package/file), or a test utility invokes the registration function a second time after package initialization.

Common situations: Cloning a neighboring databaseinsights tool and forgetting to update the const; rebasing/merging that reintroduced an identical tool type; vendor or module duplication linking the package twice under different import paths.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/9e0292abcc207168. Report an issue: GitHub.