{"record":{"id":"3dd0367705034193","repo":"gofiber/fiber","slug":"fiber-keyauth-error-uri-must-be-absolute","errorCode":null,"errorMessage":"fiber: keyauth error_uri must be absolute","messagePattern":"fiber: keyauth error_uri must be absolute","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"middleware/keyauth/config.go","lineNumber":147,"sourceCode":"\t\tcfg.Challenge = fmt.Sprintf(\"ApiKey realm=%q\", cfg.Realm)\n\t}\n\n\tif cfg.Error != \"\" {\n\t\tswitch cfg.Error {\n\t\tcase ErrorInvalidRequest, ErrorInvalidToken, ErrorInsufficientScope:\n\t\tdefault:\n\t\t\tpanic(\"fiber: keyauth unsupported error token\")\n\t\t}\n\t}\n\tif cfg.ErrorDescription != \"\" && cfg.Error == \"\" {\n\t\tpanic(\"fiber: keyauth error_description requires error\")\n\t}\n\tif cfg.ErrorURI != \"\" {\n\t\tif cfg.Error == \"\" {\n\t\t\tpanic(\"fiber: keyauth error_uri requires error\")\n\t\t}\n\t\tif u, err := url.Parse(cfg.ErrorURI); err != nil || !u.IsAbs() {\n\t\t\tpanic(\"fiber: keyauth error_uri must be absolute\")\n\t\t}\n\t}\n\tif cfg.Error == ErrorInsufficientScope {\n\t\tif cfg.Scope == \"\" {\n\t\t\tpanic(\"fiber: keyauth insufficient_scope requires scope\")\n\t\t}\n\t\tfor scope := range strings.SplitSeq(cfg.Scope, \" \") {\n\t\t\tif scope == \"\" || !isScopeToken(scope) {\n\t\t\t\tpanic(\"fiber: keyauth scope contains invalid token\")\n\t\t\t}\n\t\t}\n\t} else if cfg.Scope != \"\" {\n\t\tpanic(\"fiber: keyauth scope requires insufficient_scope error\")\n\t}\n\n\treturn cfg\n}\n","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/gofiber/fiber/blob/a105acad6c1e4576a77f01e02973f67e962bb58d/middleware/keyauth/config.go#L129-L165","documentation":"When Config.ErrorURI is set, keyauth parses it with url.Parse and requires the result to be absolute (u.IsAbs()). A relative URI panics because RFC 6750 error_uri must be an absolute URI the client can dereference. This also rejects malformed URIs that fail to parse.","triggerScenarios":"ErrorURI: \"/docs/auth\", \"docs.example.com/auth\" (no scheme), or any value where url.Parse succeeds but Scheme/Host are empty. Also triggered by a typo'd scheme like htt://.","commonSituations":"Using a site-relative docs link instead of a fully-qualified URL; building ErrorURI from a hostname variable that is sometimes empty; copy-pasting a path that omits the https:// prefix.","solutions":["Provide an absolute URL with a scheme and host, e.g. \"https://docs.example.com/auth/errors\".","Build the URL from a configured base: fmt.Sprintf(\"%s/auth/errors\", baseURL) where baseURL always includes the scheme.","If you only have a relative path, drop ErrorURI (it is optional)."],"exampleFix":"// before\napp.Use(keyauth.New(keyauth.Config{\n    Validator: v,\n    Error:     keyauth.ErrorInvalidToken,\n    ErrorURI:  \"/docs/auth\",\n}))\n\n// after\napp.Use(keyauth.New(keyauth.Config{\n    Validator: v,\n    Error:     keyauth.ErrorInvalidToken,\n    ErrorURI:  \"https://docs.example.com/auth\",\n}))","handlingStrategy":"validation","validationCode":"if cfg.ErrorURI != \"\" {\n    u, err := url.Parse(cfg.ErrorURI)\n    if err != nil || !u.IsAbs() {\n        log.Fatalf(\"keyauth: ErrorURI must be absolute, got %q\", cfg.ErrorURI)\n    }\n}","typeGuard":"func isAbsoluteURL(s string) bool {\n    u, err := url.Parse(s)\n    return err == nil && u.IsAbs()\n}","tryCatchPattern":null,"preventionTips":["Always include the scheme (https://) in ErrorURI.","Build ErrorURI from a known-absolute base URL constant.","Drop ErrorURI if you only have a relative path — it is optional."],"tags":["keyauth","oauth","rfc-6750","url","config","auth","startup-panic"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}