{"record":{"id":"b8618930991be497","repo":"googleapis/mcp-toolbox","slug":"tool-type-q-already-registered-b86189","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/oceanbasesql/oceanbasesql.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-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\tStatement          string                 `yaml:\"statement\" validate:\"required\"`\n\tParameters         parameters.Parameters  `yaml:\"parameters\"`\n\tTemplateParameters parameters.Parameters  `yaml:\"templateParameters\"`\n\tAnnotations        *tools.ToolAnnotations `yaml:\"annotations,omitempty\"`\n}\n","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/tools/oceanbase/oceanbasesql/oceanbasesql.go#L16-L52","documentation":"This is a fail-fast panic raised during package initialization. The oceanbasesql package registers its config factory under resourceType \"oceanbase-sql\" in the global toolRegistry via tools.Register() (internal/tools/tools.go:43). A false return means the type string was already claimed by another package's init(), so this init() panics — the registry must keep a one-to-one mapping between YAML `kind` values and config factories for DecodeConfig to work.","triggerScenarios":"Two init() functions register \"oceanbase-sql\": a duplicated/renamed copy of oceanbasesql still using the constant, the package linked under two import paths, or a hand-added tool reusing the built-in type string.","commonSituations":"Copying oceanbasesql (or mysqlsql) as a template and forgetting the const; merge conflicts that retain both old and new package directories; vendoring/forking the module so the package initializes twice.","solutions":["grep -rn '\"oceanbase-sql\"' to find every tools.Register call with this type; keep exactly one.","Rename the resourceType in the new/renamed tool package to a unique kebab-case value.","Remove duplicate imports and deduplicate module copies (go mod tidy, audit replace/vendor).","Run `go build ./...` and `go test ./internal/tools/oceanbase/oceanbasesql/...` to confirm the fix."],"exampleFix":"// before (forked copy)\nconst resourceType string = \"oceanbase-sql\"\n\n// after\nconst resourceType string = \"oceanbase-sql-tenant\"","handlingStrategy":"validation","validationCode":"// Verify uniqueness before building:\n// grep -rn '\"oceanbase-sql\"' --include='*.go' . | grep 'resourceType\\|tools.Register'\n// Exactly one match expected. Soft guard for forked 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":["If forking oceanbase-sql, rename resourceType (and update any YAML `kind:` usages) in the same change.","Add a registry-uniqueness unit test that fails CI on duplicate type strings.","Maintain one module copy in go.mod; run go mod tidy to remove duplicates.","Delete superseded tool packages rather than leaving them in the tree.","Run go build ./... before every PR touching internal/tools registrations."],"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"}