{"record":{"id":"8dba13857de28a15","repo":"googleapis/mcp-toolbox","slug":"tool-type-q-already-registered-8dba13","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/postgreslistavailableextensions/postgreslistavailableextensions.go","lineNumber":44,"sourceCode":"\t\"github.com/googleapis/mcp-toolbox/internal/util/parameters\"\n\t\"github.com/jackc/pgx/v5/pgxpool\"\n)\n\nconst resourceType string = \"postgres-list-available-extensions\"\n\nconst listAvailableExtensionsQuery = `\n    SELECT\n        name,\n        default_version,\n        comment as description\n    FROM\n        pg_available_extensions\n    ORDER BY name;\n`\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":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/tools/postgres/postgreslistavailableextensions/postgreslistavailableextensions.go#L26-L62","documentation":"This is a startup panic from postgreslistavailableextensions' init(): tools.Register (internal/tools/tools.go:43) returned false because the global toolRegistry already has a factory registered for the same resourceType string (\"postgres-list-available-extensions\"). The registry is populated once per tool package via init(); a repeated key means two factories claim one YAML `type`, so the process panics immediately at init time.","triggerScenarios":"Linking code where two init() functions register \"postgres-list-available-extensions\" — normally a duplicated postgreslistavailableextensions.go whose `resourceType` constant was never changed, or the same constant declared in two packages both imported.","commonSituations":"Copy-pasting the file to create a variant extensions tool and renaming only the package/directory; resolving a merge by keeping both copies; importing both upstream and a locally forked version into a custom binary.","solutions":["Search for the collision: rg '\"postgres-list-available-extensions\"' internal/ cmd/; change one `resourceType` constant to a unique string.","If the duplicate is a real new tool, rename the constant and package to its own kebab-case type.","Delete the leftover duplicate package and import.","Confirm with `go build ./...` and postgres tool tests."],"exampleFix":"// before (duplicate package)\nconst resourceType string = \"postgres-list-available-extensions\"\n// after\nconst resourceType string = \"postgres-list-available-extensions-v2\"","handlingStrategy":"validation","validationCode":"// Pre-build uniqueness check:\n//   rg -F '\"postgres-list-available-extensions\"' internal/ cmd/  # expect 1 hit\n// CI smoke test that links all tool packages and thus runs every init():\nfunc TestRegistrationsUnique(t *testing.T) {\n\t// must not panic with \"tool type %q already registered\"\n}","typeGuard":"func registrationIsUnique(root, resourceType string) bool {\n\treturn countLiteralOccurrences(root, \"\\\"\"+resourceType+\"\\\"\") == 1\n}","tryCatchPattern":null,"preventionTips":["Whenever duplicating a postgres tool file, rename the `resourceType` constant immediately.","Enforce constant == directory name (kebab-case) in code review.","Include a test that imports every tool package so duplicate init()s fail in CI.","Check for existing registrations with a literal search before adding imports.","Delete forked copies once they are no longer needed."],"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"}