{"record":{"id":"f3fb0aaf76c2b222","repo":"ory/hydra","slug":"device-challenge-is-required","errorCode":null,"errorMessage":"device_challenge is required","messagePattern":"device_challenge is required","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"cmd/cmd_perform_device_flow.go","lineNumber":159,"sourceCode":"\td := deviceSrv{cl: cl, mux: http.NewServeMux()}\n\td.mux.HandleFunc(\"GET /device\", d.GETdevice)\n\td.mux.HandleFunc(\"POST /device\", d.POSTdevice)\n\td.mux.HandleFunc(\"GET /device/done\", d.GETdone)\n\treturn &d\n}\n\ntype deviceSrv struct {\n\tcl  *openapi.APIClient\n\tmux *http.ServeMux\n}\n\nfunc (s *deviceSrv) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n\ts.mux.ServeHTTP(w, r)\n}\n\nfunc (s *deviceSrv) GETdevice(w http.ResponseWriter, r *http.Request) {\n\tif r.URL.Query().Get(\"device_challenge\") == \"\" {\n\t\thttp.Error(w, \"device_challenge is required\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\terr := userCodeTemplate.Execute(w, userCodeData{\n\t\tUserCode:        r.URL.Query().Get(\"user_code\"),\n\t\tDeviceChallenge: r.URL.Query().Get(\"device_challenge\"),\n\t})\n\tif err != nil {\n\t\thttp.Error(w, fmt.Sprintf(\"Failed to render template: %s\", err), http.StatusInternalServerError)\n\t\treturn\n\t}\n}\n\nfunc (s *deviceSrv) POSTdevice(w http.ResponseWriter, r *http.Request) {\n\tif err := r.ParseForm(); err != nil {\n\t\thttp.Error(w, fmt.Sprintf(\"Failed to parse form: %s\", err), http.StatusBadRequest)\n\t\treturn\n\t}","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/ory/hydra/blob/4174065ffb052799890f7480f5360a877a67ffc1/cmd/cmd_perform_device_flow.go#L141-L177","documentation":"The device-flow local UI (deviceSrv.GETdevice) serves the user-code page and requires the device_challenge query parameter to build the accept URL later. When it is missing, the handler responds 400 'device_challenge is required'.","triggerScenarios":"Opening the device verification URL without appending ?device_challenge=..., or with an empty value, as produced by Hydra's device authorization response (verification_uri_complete).","commonSituations":"User manually typing the verification URL from docs instead of using verification_uri_complete; URL truncation by a terminal/QR-code scanner; the CLI skipping the device_challenge query param when opening the browser; proxy or link shortener stripping query parameters.","solutions":["Open the URL exactly as returned in verification_uri_complete (or append the device_challenge query param yourself)","Re-run the device flow login to obtain a fresh device challenge and verification URL","Check that the browser/QR scanner did not strip the query string","Ensure nothing in the environment (proxy, redirect) rewrites the URL"],"exampleFix":"// before\nbrowser.Open(\"http://localhost:4445/device\")\n// after\nbrowser.Open(fmt.Sprintf(\"http://localhost:4445/device?device_challenge=%s&user_code=%s\",\n\turl.QueryEscape(challenge), url.QueryEscape(userCode)))","handlingStrategy":"validation","validationCode":"// client side: build the URL with the challenge before opening\nif deviceChallenge == \"\" {\n\treturn errors.New(\"device challenge missing; rerun the device flow\")\n}\nverifyURL := fmt.Sprintf(\"%s?device_challenge=%s\", verifyBase, url.QueryEscape(deviceChallenge))","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always open verification_uri_complete returned by Hydra, never a hand-typed URL","URL-encode query parameters when constructing verification links","Check QR codes / terminals preserve the full query string","Regenerate the challenge if it may have expired"],"tags":["http","device-flow","validation","oauth2"],"backgroundTag":"missing-required-argument","analyzedSha":"4174065ffb052799890f7480f5360a877a67ffc1","analyzedAt":"2026-09-03T14:52:41.581Z","contentChangedAt":"2026-09-03T14:52:41.581Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}