{"record":{"id":"509fcca9d5053517","repo":"googleapis/mcp-toolbox","slug":"tool-type-q-already-registered-509fcc","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/postgres/postgresexecutesql/postgresexecutesql.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/tools\"\n\t\"github.com/googleapis/mcp-toolbox/internal/util\"\n\t\"github.com/googleapis/mcp-toolbox/internal/util/parameters\"\n\t\"github.com/jackc/pgx/v5/pgxpool\"\n)\n\nconst resourceType string = \"postgres-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\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\tPostgresPool() *pgxpool.Pool\n\tRunSQL(context.Context, string, []any) (any, error)\n}\n\ntype Config struct {\n\ttools.ConfigBase `yaml:\",inline\"`","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/tools/postgres/postgresexecutesql/postgresexecutesql.go#L16-L52","documentation":"This is a startup panic from postgresexecutesql's init(): tools.Register (internal/tools/tools.go:43) returned false because the type string \"postgres-execute-sql\" was already used to register a ToolConfigFactory in the global toolRegistry. The registry forbids overwriting so that a YAML tool config's `type` unambiguously resolves to one factory; on collision the process panics during init, before main().","triggerScenarios":"Building a binary that imports two packages registering \"postgres-execute-sql\" — typically a duplicated postgresexecutesql.go whose `resourceType` constant was unchanged, or the same constant declared twice within reachable code.","commonSituations":"Copy-pasting the execute-sql tool to make a restricted variant (e.g. read-only) and renaming only the package/directory; merge conflicts resolved with both copies present; accidental import of a forked vendored copy alongside the original.","solutions":["rg '\"postgres-execute-sql\"' internal/ cmd/ to locate the second registration and make one `resourceType` unique.","For an intentional variant tool, rename the constant and package to a new kebab-case type such as \"postgres-execute-sql-readonly\".","Remove the unintended duplicate package/import.","Confirm with `go build ./...` and unit tests that the server starts."],"exampleFix":"// before (variant copy)\nconst resourceType string = \"postgres-execute-sql\"\n// after\nconst resourceType string = \"postgres-execute-sql-readonly\"","handlingStrategy":"validation","validationCode":"// Before building a custom toolbox binary, verify the type string appears exactly once:\n//   rg -F '\"postgres-execute-sql\"' internal/ cmd/   # expect 1 hit in postgresexecutesql.go\n// And keep a CI test that links all tool packages:\nfunc TestAllToolsRegister(t *testing.T) {\n\t// importing internal/tools/... packages must not panic\n}","typeGuard":"func registrationCollides(resourceType string) bool {\n\tprobe := resourceType + \"__collision_probe__\"\n\tok := tools.Register(probe, nil)\n\t_ = ok\n\t// search source for the real type string; >1 hit means a future collision\n\treturn countSourceOccurrences(resourceType) > 1\n}","tryCatchPattern":null,"preventionTips":["Never copy a tool package without renaming its `resourceType` constant in the same change.","Enforce that `resourceType` matches the package directory (kebab-case tool name per AGENTS.md).","Add a link-all-packages smoke test so this panic fires in CI rather than at startup in production.","Grep the type string before adding imports of new or forked tool packages.","Remove superseded tool copies instead of keeping both versions importable."],"tags":["go","init-panic","duplicate-registration","tool-registry","postgres"],"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"}