{"record":{"id":"c7ec42813cd6aca9","repo":"googleapis/mcp-toolbox","slug":"tool-type-q-already-registered-c7ec42","errorCode":null,"errorMessage":"tool type %q already registered","messagePattern":"tool type %q already registered","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/tools/databaseinsights/getadvancedtimeseriesquerystats/getadvancedtimeseriesquerystats.go","lineNumber":34,"sourceCode":"\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\n\tyaml \"github.com/goccy/go-yaml\"\n\t\"github.com/googleapis/mcp-toolbox/internal/sources\"\n\t\"github.com/googleapis/mcp-toolbox/internal/sources/databaseinsights\"\n\t\"github.com/googleapis/mcp-toolbox/internal/tools\"\n\t\"github.com/googleapis/mcp-toolbox/internal/util\"\n\t\"github.com/googleapis/mcp-toolbox/internal/util/parameters\"\n)\n\nconst resourceType string = \"databaseinsights-get-advanced-time-series-query-stats\"\n\nfunc init() {\n\tif !tools.Register(resourceType, newConfig) {\n\t\tpanic(fmt.Sprintf(\"tool type %q already registered\", resourceType))\n\t}\n}\n\nfunc newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (tools.ToolConfig, error) {\n\tactual := Config{ConfigBase: tools.ConfigBase{Name: name}}\n\tif err := decoder.DecodeContext(ctx, &actual); err != nil {\n\t\treturn nil, err\n\t}\n\treturn actual, nil\n}\n\ntype compatibleSource interface {\n\tFetchQueryTimeSeries(ctx context.Context, req *databaseinsights.FetchQueryTimeSeriesRequest) (*databaseinsights.FetchQueryTimeSeriesResponse, error)\n}\n\ntype Config struct {\n\ttools.ConfigBase `yaml:\",inline\"`\n\tType             string                 `yaml:\"type\" validate:\"required\"`","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/tools/databaseinsights/getadvancedtimeseriesquerystats/getadvancedtimeseriesquerystats.go#L16-L52","documentation":"This panic comes from init() in internal/tools/databaseinsights/getadvancedtimeseriesquerystats when tools.Register(resourceType, newConfig) reports the key \"databaseinsights-get-advanced-time-series-query-stats\" is already present in the global tool registry. The registry intentionally rejects duplicate tool type keys by returning false, and init() converts that into a panic so the process fails at startup rather than silently replacing an existing tool. Any process importing the package twice under duplicate keys cannot start.","triggerScenarios":"A second package or file declares the identical resourceType \"databaseinsights-get-advanced-time-series-query-stats\" and both init() functions run; or a test re-executes registration logic manually after package init already registered it.","commonSituations":"Copy-paste of a sibling databaseinsights tool with the resourceType left unchanged; a merge conflict resolution that kept two identical consts; manually calling newConfig/Register helpers in tests that already ran via init.","solutions":["Search the codebase for the string \"databaseinsights-get-advanced-time-series-query-stats\" and delete or rename the duplicate const.","Give each tool package a distinct resourceType following the <source>-<tool> naming convention.","Verify with `go vet ./...` and a clean build that only one declaration remains.","In tests, never call tools.Register for a type that package init already registered; rely on init()."],"exampleFix":"// before\nconst resourceType string = \"databaseinsights-get-advanced-time-series-query-stats\"\n// after\nconst resourceType string = \"databaseinsights-get-time-series-query-stats\" // unique key","handlingStrategy":"validation","validationCode":"const want = \"databaseinsights-get-advanced-time-series-query-stats\"\n// pre-build check: go run ./cmd/checkdup or a repo grep in CI\nif err := exec.Command(\"git\", \"grep\", \"-n\", want, \"--\", \"*.go\").Run(); err == nil {\n    // review every hit; more than one const declaration is a bug\n    _ = err\n}","typeGuard":null,"tryCatchPattern":"func safeInit() {\n    defer func() {\n        if r := recover(); r != nil {\n            log.Fatalf(\"duplicate tool type registration: %v\", r)\n        }\n    }()\n    if !tools.Register(resourceType, newConfig) {\n        return // or fail with a controlled error\n    }\n}","preventionTips":["Use a unique resourceType per package; never copy-paste a sibling const without renaming.","CI grep for the exact resourceType string to detect duplicates before merge.","Register tools only from package init().","Avoid importing the same package under two module versions (keep go.mod tidy).","Add a startup smoke test that imports all tool packages once."],"tags":["go","panic","init","tool-registry","duplicate-registration"],"backgroundTag":"duplicate-tool-type-registration","analyzedSha":"8cc6e09de2ad7b8bffc77751799585a1401a48eb","analyzedAt":"2026-09-05T01:10:36.887Z","contentChangedAt":"2026-09-05T01:10:36.887Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}