{"record":{"id":"3ce4307024719ba6","repo":"googleapis/mcp-toolbox","slug":"tool-type-q-already-registered-3ce430","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/oracle/oraclesql/oraclesql.go","lineNumber":22,"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 = \"oracle-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\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\tOracleDB() *sql.DB\n\tRunSQL(context.Context, string, []any, bool) (any, error)\n}\n\ntype Config struct {\n\ttools.ConfigBase   `yaml:\",inline\"`","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/tools/oracle/oraclesql/oraclesql.go#L4-L40","documentation":"This is a startup panic thrown by the tool package's init() when tools.Register (internal/tools/tools.go:43) detects that the shared toolRegistry map already holds a factory for the type string. Each tool package registers a unique `resourceType` constant at init time; registering \"oracle-sql\" twice means two factories claim the same YAML `type`, so the process panics rather than silently overwriting an existing registration. The failure happens before main() runs.","triggerScenarios":"Importing internal/tools/oracle/oraclesql (resourceType \"oracle-sql\") into a binary that also imports another package calling tools.Register with the same string — usually a duplicated/renamed copy of oraclesql.go whose `resourceType` constant was not changed, or a same-named constant declared in two files of one package.","commonSituations":"Copy-pasting oraclesql.go to create a variant Oracle tool and renaming only the directory; a merge that kept both an old and new copy of the package; accidentally importing the same tool package under an alias twice is safe, but importing a forked copy is not.","solutions":["Search the codebase for a second \"oracle-sql\" registration (rg '\"oracle-sql\"' internal/ cmd/) and make one `resourceType` constant unique.","For an intentional variant, rename the `resourceType` constant (and package) to a distinct kebab-case tool type such as \"oracle-sql-readonly\".","Remove the duplicate/forked package and its import if it is unintended dead code.","Run `go build ./...` and `go test ./internal/tools/...` to verify startup succeeds."],"exampleFix":"// before (forked package)\nconst resourceType string = \"oracle-sql\"\n// after\nconst resourceType string = \"oracle-sql-readonly\"","handlingStrategy":"validation","validationCode":"// In a CI check or pre-build script, assert the type string is registered exactly once:\n//   go test -run TestUniqueToolTypes ./internal/tools/...\n// or search the tree:\n//   rg -F '\"oracle-sql\"' internal/ cmd/   # expect exactly one hit in internal/tools/oracle/oraclesql/oraclesql.go","typeGuard":"// Pre-registration guard usable before shipping a new tool package:\nfunc isTypeStringUnique(sourceTree string, typ string) bool {\n\t// count literal occurrences of `\"oracle-sql\"` in *.go; return count <= 1\n\treturn countLiteral(sourceTree, \"\\\"\"+typ+\"\\\"\") <= 1\n}","tryCatchPattern":null,"preventionTips":["Rename the `resourceType` constant whenever you fork or copy a tool package.","Keep `resourceType` identical to the package's directory name to make drift obvious in review.","Add a CI/test step that imports every tool package so duplicate registrations fail fast in CI, not at customer startup.","Grep for the type string before adding any import that might contain a second registration.","Avoid alias-importing forked/vendored copies of tool packages into the same binary."],"tags":["go","init-panic","duplicate-registration","tool-registry"],"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"}