{"record":{"id":"ff68630375a28df2","repo":"theonedev/onedev","slug":"unsolicited-discord-api-response","errorCode":null,"errorMessage":"Unsolicited discord api response","messagePattern":"Unsolicited discord api response","errorType":"exception","errorClass":"AuthenticationException","httpStatus":null,"severity":"error","filePath":"server-plugin/server-plugin-sso-discord/src/main/java/io/onedev/server/plugin/sso/discord/DiscordConnector.java","lineNumber":165,"sourceCode":"\t\t} catch (IOException | JSONException e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t\n\tprivate String getScopes() {\n\t\tString scopes = \"identify email\";\n\t\tif (!StringUtils.isEmpty(this.serverId)) {\n\t\t\tscopes += \" guilds\"; \n\t\t}\n\t\t\n\t\treturn scopes;\n\t}\n\t\n\tprivate Request getCachedApiRequest() {\n\t\tRequest metadata = (Request) Session.get().getAttribute(SESSION_ATTR_API_REQUEST);\n\t\t\n\t\tif (metadata == null) {\n\t\t\tthrow new AuthenticationException(_T(\"Unsolicited discord api response\"));\n\t\t}\n\t\t\n\t\treturn metadata;\n\t}\n}\n","sourceCodeStart":147,"sourceCodeEnd":171,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-plugin/server-plugin-sso-discord/src/main/java/io/onedev/server/plugin/sso/discord/DiscordConnector.java#L147-L171","documentation":"Thrown by getCachedApiRequest when the Wicket session holds no cached Discord OAuth request metadata while the connector is handling an API callback. Since the connector only accepts callbacks for authorization flows it initiated (state is stored in the session), a callback without that cached request is deemed unsolicited and rejected.","triggerScenarios":"A request hits the Discord SSO callback handling path (via apiRequest -> getCachedApiRequest) but SESSION_ATTR_API_REQUEST was never set — e.g. the callback URL was opened directly, the session expired/was recreated between initiating login and the redirect, or a different server node handled the callback than the one that started the flow.","commonSituations":"Session cookie lost or blocked; login initiated on one OneDev node and callback routed to another in a load-balanced cluster without sticky sessions; user bookmarks/reloads the callback URL; long delay at Discord consent page causing session timeout.","solutions":["Restart the SSO login from the sign-in button so a fresh Discord API request is cached in the session.","Ensure sticky sessions (or a shared session store) when running multiple OneDev nodes behind a load balancer.","Enable browser cookies for the OneDev domain.","Increase session timeout or complete the Discord consent promptly to avoid session expiry mid-flow."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    auth = connector.handleAuthResponse(...);\n} catch (AuthenticationException e) {\n    if (e.getMessage().contains(\"Unsolicited discord api response\")) {\n        // restart login flow from the sign-in button\n    }\n}","preventionTips":["Use sticky sessions or shared session storage in clustered deployments.","Never open the SSO callback URL directly.","Keep session timeout longer than the Discord consent flow.","Ensure cookies are not blocked by browser privacy settings."],"tags":["oauth","sso","session","discord","state-mismatch"],"backgroundTag":"oauth-state-mismatch","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}