{"record":{"id":"1d42c9eaffe7dad0","repo":"googleapis/mcp-toolbox","slug":"tool-type-q-already-registered-1d42c9","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/oceanbase/oceanbaseexecutesql/oceanbaseexecutesql.go","lineNumber":34,"sourceCode":"\nimport (\n\t\"context\"\n\t\"database/sql\"\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/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 = \"oceanbase-execute-sql\"\n\nfunc init() {\n\tif !tools.Register(resourceType, newConfig) {\n\t\tpanic(fmt.Sprintf(\"tool type %q already registered\", resourceType))\n\t}\n}\n\ntype compatibleSource interface {\n\tOceanBasePool() *sql.DB\n\tRunSQL(context.Context, string, []any) (any, error)\n}\n\ntype Config struct {\n\ttools.ConfigBase `yaml:\",inline\"`\n\tType             string                 `yaml:\"type\" validate:\"required\"`\n\tSource           string                 `yaml:\"source\" validate:\"required\"`\n\tAnnotations      *tools.ToolAnnotations `yaml:\"annotations,omitempty\"`\n}\n\n// validate interface\nvar _ tools.ToolConfig = Config{}\n","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/tools/oceanbase/oceanbaseexecutesql/oceanbaseexecutesql.go#L16-L52","documentation":"This is a fail-fast panic raised during package initialization. The oceanbaseexecutesql package registers its factory under resourceType \"oceanbase-execute-sql\" in the global toolRegistry via tools.Register() (internal/tools/tools.go:43). When the registry map already holds that key (Register returns false), init() panics so duplicate tool-type claims are caught immediately at startup instead of one factory silently shadowing the other.","triggerScenarios":"Another init() calls tools.Register(\"oceanbase-execute-sql\", ...): a copy of this package left after a rename, the package imported under two module paths (replace/fork/vendor), or a custom tool reusing this type string.","commonSituations":"Template-copying oceanbaseexecutesql for a new OceanBase tool and leaving the const unchanged; a rebase duplicating the package directory; two versions of the toolbox module both linked into the binary.","solutions":["grep -rn 'oceanbase-execute-sql' to locate both registrations; assign the duplicate a unique resourceType.","Remove the duplicate import or delete the obsolete package copy.","Run go mod tidy and check replace directives / vendor for duplicates.","Verify with `go build ./...` and `go test ./internal/tools/oceanbase/...`."],"exampleFix":"// before\ncopied package: const resourceType string = \"oceanbase-execute-sql\"\n\n// after\nconst resourceType string = \"oceanbase-execute-sql-readonly\" // unique to the new tool","handlingStrategy":"validation","validationCode":"// Verify uniqueness before building:\n// grep -rn '\"oceanbase-execute-sql\"' --include='*.go' . | grep 'resourceType\\|tools.Register'\n// Exactly one match expected. Soft guard for custom tools:\nfunc init() {\n\tif !tools.Register(resourceType, newConfig) {\n\t\tfmt.Printf(\"WARNING: %s already registered; skipping duplicate init\\n\", resourceType)\n\t\treturn\n\t}\n}","typeGuard":"func isRegistered(resourceType string) bool {\n\t_, exists := registrySnapshot[resourceType]\n\treturn exists\n}","tryCatchPattern":"// Recover at the process boundary:\nfunc main() {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tif s, ok := r.(string); ok && strings.Contains(s, \"already registered\") {\n\t\t\t\tlog.Fatalf(\"duplicate tool registration: %s\", s)\n\t\t\t}\n\t\t\tpanic(r)\n\t\t}\n\t}()\n\trootCmd.Execute()\n}","preventionTips":["Rename resourceType, package, and directory together when deriving a new OceanBase tool from an existing one.","Add a CI test asserting all registered resourceType values are unique.","After rebases or merges, run go build ./... to surface duplicate registrations immediately.","Keep go.mod free of overlapping replace/vendor copies of the module.","grep the type string before committing changes to tool packages."],"tags":["go","init-panic","tool-registry","duplicate-registration","oceanbase"],"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"}