{"record":{"id":"e5e08d5e318c6e33","repo":"googleapis/mcp-toolbox","slug":"tool-type-q-already-registered-e5e08d","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/neo4j/neo4jschema/neo4jschema.go","lineNumber":41,"sourceCode":"\n\t\"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/tools/neo4j/neo4jschema/cache\"\n\t\"github.com/googleapis/mcp-toolbox/internal/tools/neo4j/neo4jschema/helpers\"\n\t\"github.com/googleapis/mcp-toolbox/internal/tools/neo4j/neo4jschema/types\"\n\t\"github.com/googleapis/mcp-toolbox/internal/util\"\n\t\"github.com/googleapis/mcp-toolbox/internal/util/parameters\"\n\t\"github.com/neo4j/neo4j-go-driver/v6/neo4j\"\n)\n\n// type defines the unique identifier for this tool.\nconst resourceType string = \"neo4j-schema\"\n\n// init registers the tool with the application's tool registry when the package is initialized.\nfunc init() {\n\tif !tools.Register(resourceType, newConfig) {\n\t\tpanic(fmt.Sprintf(\"tool type %q already registered\", resourceType))\n\t}\n}\n\n// newConfig decodes a YAML configuration into a Config struct.\n// This function is called by the tool registry to create a new configuration object.\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\n// compatibleSource defines the interface a data source must implement to be used by this tool.\n// It ensures that the source can provide a Neo4j driver and database name.\ntype compatibleSource interface {\n\tNeo4jDriver() neo4j.Driver\n\tNeo4jDatabase() string","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/tools/neo4j/neo4jschema/neo4jschema.go#L23-L59","documentation":"This is a fail-fast panic raised during package initialization. The neo4jschema package registers its factory under resourceType \"neo4j-schema\" in the global toolRegistry via tools.Register() (internal/tools/tools.go:43). Register() returns false when another init() already stored that type key, and init() deliberately panics (as its comment notes, this is the application's tool registry) because two factories for one `kind` would make YAML tool config decoding nondeterministic.","triggerScenarios":"Two packages register \"neo4j-schema\": a duplicated copy of neo4jschema still carrying the const, the package linked twice via different module paths, or a new schema-inspection tool reusing the built-in type string.","commonSituations":"Copying the schema tool as a template for a new introspection tool without renaming the type; a merge conflict resolution that kept both old and new package directories; vendoring duplicates of the module.","solutions":["grep -rn '\"neo4j-schema\"' to find all registering packages; keep one and give the other a unique resourceType.","Delete the obsolete duplicate package or remove its import from cmd/root.go.","Deduplicate module versions (go mod tidy; review replace/vendor).","Verify with `go build ./...` and `go test ./internal/tools/neo4j/neo4jschema/...`."],"exampleFix":"// before\nconst resourceType string = \"neo4j-schema\" // duplicated\n\n// after\nconst resourceType string = \"neo4j-schema\" // original only; new tool uses \"neo4j-schema-deep\"","handlingStrategy":"validation","validationCode":"// Verify uniqueness before building:\n// grep -rn '\"neo4j-schema\"' --include='*.go' . | grep 'resourceType\\|tools.Register'\n// Exactly one match expected. Soft guard for custom 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":["Give every new Neo4j tool a unique kebab-case resourceType per project naming conventions.","Add a registry-uniqueness test to internal/tools to fail CI on duplicate type strings.","Resolve merge conflicts by deleting (not keeping) superseded tool packages.","Keep a single module copy in go.mod; run go mod tidy after updates.","grep the type string before committing registration changes."],"tags":["go","init-panic","tool-registry","duplicate-registration","neo4j"],"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"}