{"record":{"id":"7e004d02d61881fa","repo":"sipeed/picoclaw","slug":"failed-to-request-device-code-v","errorCode":null,"errorMessage":"failed to request device code: %v","messagePattern":"failed to request device code: (.+?)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"web/backend/api/oauth.go","lineNumber":237,"sourceCode":"\t\t}\n\t\tif err := h.persistCredentialAndConfig(provider, oauthMethodToken, cred); err != nil {\n\t\t\thttp.Error(w, fmt.Sprintf(\"token login failed: %v\", err), http.StatusInternalServerError)\n\t\t\treturn\n\t\t}\n\n\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t_ = json.NewEncoder(w).Encode(map[string]any{\n\t\t\t\"status\":   \"ok\",\n\t\t\t\"provider\": provider,\n\t\t\t\"method\":   method,\n\t\t})\n\t\treturn\n\n\tcase oauthMethodDeviceCode:\n\t\tcfg := auth.OpenAIOAuthConfig()\n\t\tinfo, err := oauthRequestDeviceCode(cfg)\n\t\tif err != nil {\n\t\t\thttp.Error(w, fmt.Sprintf(\"failed to request device code: %v\", err), http.StatusInternalServerError)\n\t\t\treturn\n\t\t}\n\n\t\tnow := oauthNow()\n\t\tflow := &oauthFlow{\n\t\t\tID:           newOAuthFlowID(),\n\t\t\tProvider:     provider,\n\t\t\tMethod:       method,\n\t\t\tStatus:       oauthFlowPending,\n\t\t\tCreatedAt:    now,\n\t\t\tUpdatedAt:    now,\n\t\t\tExpiresAt:    now.Add(oauthDeviceCodeFlowTTL),\n\t\t\tDeviceAuthID: info.DeviceAuthID,\n\t\t\tUserCode:     info.UserCode,\n\t\t\tVerifyURL:    info.VerifyURL,\n\t\t\tInterval:     info.Interval,\n\t\t}\n\t\th.storeOAuthFlow(flow)","sourceCodeStart":219,"sourceCodeEnd":255,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/web/backend/api/oauth.go#L219-L255","documentation":"Returned as HTTP 500 by POST /api/oauth/login when method is \"device_code\" and auth.RequestDeviceCode fails. That helper POSTs JSON {\"client_id\": ...} to https://auth.openai.com/api/accounts/deviceauth/usercode using the OpenAI OAuth client config; failure means either the outbound HTTP request itself failed (DNS, proxy, timeout) or the endpoint returned a non-2xx status. The %v detail distinguishes \"requesting device code: ...\" (transport) from an HTTP status body.","triggerScenarios":"POST /api/oauth/login {\"provider\":\"openai\",\"method\":\"device_code\"} while the host has no route to auth.openai.com, an HTTPS proxy is required but unset, a corporate firewall TLS-intercepts auth.openai.com, or OpenAI's device authorization endpoint returns 4xx/5xx.","commonSituations":"Air-gapped or egress-filtered deployment; HTTPS_PROXY/HTTP_PROXY not set in the backend's environment; OpenAI auth outage; captive portal intercepting the request; DNS failure inside a container.","solutions":["Verify egress from the backend host: curl -sS -o /dev/null -w '%{http_code}' https://auth.openai.com/api/accounts/deviceauth/usercode.","Set HTTPS_PROXY/HTTP_PROXY (and NO_PROXY) in the backend process environment and restart it if a proxy is required.","Retry after a short wait — a 5xx from the endpoint or a transient network failure is often short-lived.","Check backend logs (logger.Errorf) for the wrapped cause; TLS certificate errors point at interception, DNS errors at resolver config.","If device_code cannot work in the environment, fall back to method \"token\" for openai, which needs no outbound call."],"exampleFix":"# before: backend started without proxy awareness\nsystemctl start picoclaw-web  # 500 failed to request device code: ... dial tcp ... i/o timeout\n\n# after\n# /etc/systemd/system/picoclaw-web.service.d/proxy.conf\n[Service]\nEnvironment=\"HTTPS_PROXY=http://proxy.corp:3128\"\nEnvironment=\"NO_PROXY=localhost,127.0.0.1\"","handlingStrategy":"retry","validationCode":"await fetch('https://auth.openai.com', {method:'HEAD', signal: AbortSignal.timeout(5000)}); // preflight egress before offering device_code","typeGuard":null,"tryCatchPattern":"async function requestDeviceCode(provider, attempt = 0) {\n  const res = await fetch('/api/oauth/login', {method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({provider, method:'device_code'})});\n  if (res.status === 500) {\n    const { message } = await res.json();\n    if (/device code/i.test(message ?? '') && attempt < 3) {\n      await new Promise(r => setTimeout(r, 1500 * 2 ** attempt));\n      return requestDeviceCode(provider, attempt + 1);\n    }\n    throw new Error(message);\n  }\n  return res.json();\n}","preventionTips":["Ensure the backend host has egress to auth.openai.com (proxies set via HTTPS_PROXY if required) before offering device-code login.","Offer token login as an alternative when device code cannot be requested.","Watch backend logs for the wrapped cause to distinguish network from endpoint failures."],"tags":["oauth","http-500","device-code","network","openai"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}