{"id":"ca3555c19bffa8bc","repo":"gofiber/fiber","slug":"add-invalid-http-method-s","errorCode":null,"errorMessage":"add: invalid http method %s\n","messagePattern":"add: invalid http method (.+?)\n","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"router.go","lineNumber":1014,"sourceCode":"\t}\n\tpathPretty := pathRaw\n\tif !app.config.CaseSensitive {\n\t\tpathPretty = utilsstrings.ToLower(pathPretty)\n\t}\n\tif !app.config.StrictRouting && len(pathPretty) > 1 {\n\t\tpathPretty = utils.TrimRight(pathPretty, '/')\n\t}\n\tpathClean := RemoveEscapeChar(pathPretty)\n\n\tparsedRaw := parseRoute(pathRaw, app.config.RegexHandler, app.customConstraints...)\n\tparsedPretty := parseRoute(pathPretty, app.config.RegexHandler, app.customConstraints...)\n\n\tisMount := group != nil && group.app != app\n\n\tfor _, method := range methods {\n\t\tmethod = utilsstrings.ToUpper(method)\n\t\tif method != methodUse && app.methodInt(method) == -1 {\n\t\t\tpanic(fmt.Sprintf(\"add: invalid http method %s\\n\", method))\n\t\t}\n\n\t\tisUse := method == methodUse\n\t\tisStar := pathClean == \"/*\"\n\t\tisRoot := pathClean == \"/\"\n\n\t\troute := Route{\n\t\t\tuse:           isUse,\n\t\t\tmount:         isMount,\n\t\t\tstar:          isStar,\n\t\t\troot:          isRoot,\n\t\t\tcaseSensitive: app.config.CaseSensitive,\n\n\t\t\tpath:        pathClean,\n\t\t\trouteParser: parsedPretty,\n\t\t\tParams:      parsedRaw.params,\n\t\t\tgroup:       group,\n","sourceCodeStart":996,"sourceCodeEnd":1032,"githubUrl":"https://github.com/gofiber/fiber/blob/9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c/router.go#L996-L1032","documentation":"Raised by App.register (router.go:1014) when a method string is neither the pseudo-method \"USE\" nor resolvable by App.methodInt. methodInt returns -1 for any token not in the built-in set (GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH, QUERY), or — when Config.RequestMethods is customized — not present in app.config.RequestMethods (the slices.Index path at helpers.go:1243). App.Add, App.All, Group, Mount and Domain registration all funnel into register, so any of them can trip this guard. The check runs at route-registration time, so the process panics during startup before it serves traffic.","triggerScenarios":"Call app.Add([]string{\"FOO\"}, \"/x\", h) or pass a typo such as \"GETT\"/\"POSTT\", an empty string (ToUpper yields \"\"), or a custom method name that was never added to fiber.Config.RequestMethods. Also reachable via App.All, group.Get-like helpers that derive methods dynamically, or Mount/Domain paths — all invoke register and hit line 1013-1014.","commonSituations":"Typos in method string literals; passing a runtime-derived method (from config, c.Method(), or a header) into Add without validation; assuming non-RFC verbs like PURGE/LINK/UNLINK are supported out of the box; or customizing Config.RequestMethods and then forgetting to declare a method there before registering it (note: once RequestMethods is non-empty, methodInt uses slices.Index over it, so even GET must be listed).","solutions":["Pass the fiber.Method* constants (MethodGet, MethodPost, …) instead of hand-typed strings so spelling is guaranteed.","For custom verbs, declare them in fiber.Config.RequestMethods before registering routes that use them.","If the method originates from dynamic/untrusted input, validate it against an allow-list before calling Add and reject with 405 rather than registering.","Inspect the methods slice for empty strings or stray whitespace — ToUpper normalizes case but does not trim spaces."],"exampleFix":"// before — typo panics at boot\napp.Add([]string{\"POSTT\"}, \"/users\", h)\n\n// after — use the constant\napp.Add([]string{fiber.MethodPost}, \"/users\", h)","handlingStrategy":"validation","validationCode":"var allowedMethods = map[string]struct{}{\n\tfiber.MethodGet: {}, fiber.MethodHead: {}, fiber.MethodPost: {}, fiber.MethodPut: {},\n\tfiber.MethodPatch: {}, fiber.MethodDelete: {}, fiber.MethodConnect: {},\n\tfiber.MethodOptions: {}, fiber.MethodTrace: {}, fiber.MethodQuery: {},\n}\n// add any custom methods declared in Config.RequestMethods\nfor _, m := range app.Config().RequestMethods {\n\tallowedMethods[m] = struct{}{}\n}\nfor _, m := range methods {\n\tif _, ok := allowedMethods[strings.ToUpper(m)]; !ok {\n\t\treturn fmt.Errorf(\"rejecting registration: unsupported method %q\", m)\n\t}\n}\napp.Add(methods, \"/x\", h)","typeGuard":null,"tryCatchPattern":"defer func() {\n\tif r := recover(); r != nil {\n\t\tlog.Printf(\"route registration failed: %v\", r)\n\t\t// do not re-register; surface the bad method to the caller\n\t}\n}()\napp.Add(methods, \"/x\", h)","preventionTips":["Always pass fiber.Method* constants instead of string literals.","Validate any method originating from config, headers, or c.Method() against an allow-list before Add.","When customizing Config.RequestMethods, declare every custom verb there before registering it.","Add a unit test that exercises each registration entry point to catch bad methods at CI time, not boot time."],"tags":["router","http-method","startup","panic","registration"],"analyzedSha":"9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c","analyzedAt":"2026-08-04T21:44:03.395Z","schemaVersion":2}