{"id":"ef48cda9d733b4d2","repo":"gin-gonic/gin","slug":"handlers-are-already-registered-for-path-fullpa","errorCode":null,"errorMessage":"handlers are already registered for path '${fullPath}'","messagePattern":"handlers are already registered for path '(.+?)'","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tree.go","lineNumber":243,"sourceCode":"\t\t\t\tpathSeg := path\n\t\t\t\tif n.nType != catchAll {\n\t\t\t\t\tpathSeg, _, _ = strings.Cut(pathSeg, \"/\")\n\t\t\t\t}\n\t\t\t\tprefix := fullPath[:strings.Index(fullPath, pathSeg)] + n.path\n\t\t\t\tpanic(\"'\" + pathSeg +\n\t\t\t\t\t\"' in new path '\" + fullPath +\n\t\t\t\t\t\"' conflicts with existing wildcard '\" + n.path +\n\t\t\t\t\t\"' in existing prefix '\" + prefix +\n\t\t\t\t\t\"'\")\n\t\t\t}\n\n\t\t\tn.insertChild(path, fullPath, handlers)\n\t\t\treturn\n\t\t}\n\n\t\t// Otherwise add handle to current node\n\t\tif n.handlers != nil {\n\t\t\tpanic(\"handlers are already registered for path '\" + fullPath + \"'\")\n\t\t}\n\t\tn.handlers = handlers\n\t\tn.fullPath = fullPath\n\t\treturn\n\t}\n}\n\n// Search for a wildcard segment and check the name for invalid characters.\n// Returns -1 as index, if no wildcard was found.\nfunc findWildcard(path string) (wildcard string, i int, valid bool) {\n\t// Find start\n\tescapeColon := false\n\tfor start, c := range []byte(path) {\n\t\tif escapeColon {\n\t\t\tescapeColon = false\n\t\t\tif c == ':' {\n\t\t\t\tcontinue\n\t\t\t}","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/gin-gonic/gin/blob/34dac209ffb6ef85cc78c5d217bbb7ad001d68fd/tree.go#L225-L261","documentation":"Thrown by (*node).addRoute in tree.go:243 when addRoute reaches a leaf node that already has handlers attached. Gin's radix tree stores at most one handler chain per (method, path) pair, so registering the exact same method+path twice is treated as a programmer error rather than silently overwriting. The panic message echoes the duplicated fullPath so you can locate the offending registration.","triggerScenarios":"Calling router.GET(\"/healthz\", h) twice on the same Engine; calling router.Handle(\"GET\", \"/items\", h) after a previous router.GET(\"/items\", ...) (same method+path); mounting a sub-router via router.Group(\"\").GET(\"/\", h) when the parent already mapped \"/\"; or auto-generated route registration loops that emit the same entry more than once.","commonSituations":"Two init() blocks or two packages both registering the same health-check endpoint; route lists generated from config where a duplicate slips in; refactoring that moves a handler into a group without removing the old top-level call; merging PRs that each add the same route.","solutions":["Search the codebase for the exact path string from the panic message — there will be two registrations; delete or rename one.","If the duplication comes from generated code, dedupe the source list (map[string]bool) before iterating.","If you intend multiple handlers, combine them into one handler chain or use router.Use(...) middleware instead of re-registering the path.","Add a startup self-test that builds the router and asserts no panic; CI catches the regression before deploy."],"exampleFix":"// before\nrouter.GET(\"/healthz\", healthHandler)\n// ...elsewhere in the codebase...\nrouter.GET(\"/healthz\", healthHandler) // panics\n\n// after — keep a single registration, share via middleware if needed\nrouter.GET(\"/healthz\", healthHandler)","handlingStrategy":"validation","validationCode":"// Detect duplicate (method, path) registrations before the engine is built.\nfunc assertNoDuplicates(routes []struct{ Method, Path string }) error {\n    seen := make(map[string]string) // key \"METHOD PATH\" -> handler name\n    for _, r := range routes {\n        k := r.Method + \" \" + r.Path\n        if _, ok := seen[k]; ok {\n            return fmt.Errorf(\"duplicate route %s\", k)\n        }\n        seen[k] = \"\"\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"func safeHandle(e *gin.Engine, method, path string, h gin.HandlerFunc) (err error) {\n    defer func() {\n        if r := recover(); r != nil {\n            err = fmt.Errorf(\"duplicate route %s %s: %v\", method, path, r)\n        }\n    }()\n    e.Handle(method, path, h)\n    return nil\n}","preventionTips":["Declare all routes in a single slice or table driven by config so duplicates are visible and dedupable.","Generate route tables from a single source of truth (OpenAPI spec, codegen) rather than hand-registering.","Add a unit test that constructs the production Engine; duplicate routes panic during testing.","Treat the panic message's fullPath as the literal string to grep for in the repo — there will be exactly two occurrences."],"tags":["routing","duplicate-route","gin","startup-panic"],"analyzedSha":"34dac209ffb6ef85cc78c5d217bbb7ad001d68fd","analyzedAt":"2026-08-04T21:26:18.438Z","schemaVersion":2}