{"record":{"id":"852c740f84f97614","repo":"googleapis/mcp-toolbox","slug":"tool-type-q-already-registered-852c74","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/postgreslistindexes/postgreslistindexes.go","lineNumber":80,"sourceCode":"            AND s.schemaname NOT LIKE 'pg_temp_%'\n    )\n    SELECT *\n    FROM IndexDetails\n    WHERE\n        ($1::text IS NULL OR schema_name LIKE '%' || $1 || '%')\n        AND ($2::text IS NULL OR table_name LIKE '%' || $2 || '%')\n        AND ($3::text IS NULL OR index_name LIKE '%' || $3 || '%')\n        AND ($4::boolean IS NOT TRUE OR is_used IS FALSE)\n    ORDER BY\n        schema_name,\n        table_name,\n        index_name\n    LIMIT COALESCE($5::int, 50);\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":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/tools/postgres/postgreslistindexes/postgreslistindexes.go#L62-L98","documentation":"This is a startup panic from postgreslistindexes' init(): tools.Register (internal/tools/tools.go:43) returned false because the global toolRegistry map already contains a factory keyed by the package's resourceType string (\"postgres-list-indexes\"). Each tool type must be uniquely registered so YAML configs decode unambiguously; a collision is treated as a fatal programming error and panics at init time.","triggerScenarios":"Linking a binary where two init() functions register \"postgres-list-indexes\" — most often a copy-pasted postgreslistindexes.go whose `resourceType` constant was left unchanged, or the same constant declared in two imported packages.","commonSituations":"Cloning the list-indexes tool for a schema-scoped or limited variant and renaming only the package/directory; a bad merge leaving duplicate packages; importing a forked copy alongside the original in a custom toolbox build.","solutions":["Locate the duplicate with rg '\"postgres-list-indexes\"' internal/ cmd/ and make one `resourceType` constant unique.","If the copy is an intentional new tool, rename the constant and package to a distinct kebab-case type (e.g. \"postgres-list-indexes-invalid\").","Delete the redundant copied package and its import.","Run `go build ./...` and postgres tool tests to confirm startup."],"exampleFix":"// before (cloned tool)\nconst resourceType string = \"postgres-list-indexes\"\n// after\nconst resourceType string = \"postgres-list-indexes-invalid\"","handlingStrategy":"validation","validationCode":"// Uniqueness check before build:\n//   rg -F '\"postgres-list-indexes\"' internal/ cmd/  # expect exactly 1 hit\n// CI smoke test linking every tool package:\nfunc TestToolInitSmoke(t *testing.T) {\n\t// duplicate registrations panic here; test must pass\n}","typeGuard":"func occursOnce(root, resourceType string) bool {\n\treturn countLiterals(root, \"\\\"\"+resourceType+\"\\\"\") == 1\n}","tryCatchPattern":null,"preventionTips":["Rename `resourceType` whenever you clone a tool package; do it before any other edits.","Keep the constant equal to the tool's kebab-case directory name.","Maintain a test that imports all tool packages so duplicate init() panics surface in CI.","Grep for the exact type literal before adding imports of new or forked packages.","Avoid dual-importing upstream and forked versions of the same tool."],"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"}