{"record":{"id":"9b6bf96e951c1c34","repo":"justauth/JustAuth","slug":"name-message","errorCode":null,"errorMessage":"${name}, ${message}","messagePattern":"\\$\\{name\\}, \\$\\{message\\}","errorType":"exception","errorClass":"AuthException","httpStatus":null,"severity":"error","filePath":"src/main/java/me/zhyd/oauth/request/AuthTeambitionRequest.java","lineNumber":118,"sourceCode":"        this.checkResponse(refreshTokenObject);\n\n        return AuthResponse.<AuthToken>builder()\n            .code(AuthResponseStatus.SUCCESS.getCode())\n            .data(AuthToken.builder()\n                .accessToken(refreshTokenObject.getString(\"access_token\"))\n                .refreshToken(refreshTokenObject.getString(\"refresh_token\"))\n                .build())\n            .build();\n    }\n\n    /**\n     * 检查响应内容是否正确\n     *\n     * @param object 请求响应内容\n     */\n    private void checkResponse(JSONObject object) {\n        if ((object.containsKey(\"message\") && object.containsKey(\"name\"))) {\n            throw new AuthException(object.getString(\"name\") + \", \" + object.getString(\"message\"));\n        }\n    }\n}\n","sourceCodeStart":100,"sourceCodeEnd":122,"githubUrl":"https://github.com/justauth/JustAuth/blob/694bbf1b010d93404e3bfb4824d90e9ddfaebebb/src/main/java/me/zhyd/oauth/request/AuthTeambitionRequest.java#L100-L122","documentation":"AuthTeambitionRequest.checkResponse throws AuthException with 'name, message' concatenated from the JSON payload when BOTH `message` and `name` keys are present. Teambition signals errors with an error object containing a machine name (e.g. 'InvalidAccessToken') and a human message; JustAuth joins them into one string. No numeric code is attached.","triggerScenarios":"Any Teambition API call (access token exchange, user info, refresh) whose response body contains both name and message — typical values: InvalidAccessToken, InvalidRefreshToken, BadRequest, or FlowControl during rate limiting.","commonSituations":"Expired or revoked Teambition access token (sessions are short-lived); reusing a refresh token after it was already rotated; Teambition client_id/client_secret mismatch; API quota exhausted ('FlowControl' name).","solutions":["Parse the leading name from the message: 'InvalidAccessToken'/'InvalidRefreshToken' → re-authenticate via authorize(state); 'FlowControl' → back off and retry with exponential delay.","Verify clientId/clientSecret in AuthConfig against the Teambition app settings.","Ensure refresh tokens are single-use: always store the new refresh token returned by refresh().","Wrap calls in retry-with-backoff for FlowControl only, never for credential errors."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// validate token freshness before Teambition calls\nif (token.getExpireTime() != null && System.currentTimeMillis() > token.getExpireTime() - 60_000L) {\n    token = teambitionRequest.refresh(token); // refresh proactively\n}","typeGuard":null,"tryCatchPattern":"// retry-with-backoff, but only for rate limiting\nfor (int i = 0; i < 3; i++) {\n    try { return request.getUserInfo(token); }\n    catch (AuthException e) {\n        String m = String.valueOf(e.getMessage());\n        if (m.startsWith(\"FlowControl\") && i < 2) { Thread.sleep((1L << i) * 500); continue; }\n        if (m.startsWith(\"InvalidAccessToken\") || m.startsWith(\"InvalidRefreshToken\")) {\n            redirect(request.authorize(state));\n        }\n        throw e;\n    }\n}","preventionTips":["Refresh Teambition tokens proactively before expiry rather than reactively.","Treat refresh tokens as rotating single-use values.","Wrap Teambition calls in a rate-limit-aware retry decorator."],"tags":["justauth","teambition","oauth","api-error","rate-limit"],"backgroundTag":null,"analyzedSha":"694bbf1b010d93404e3bfb4824d90e9ddfaebebb","analyzedAt":"2026-08-14T15:16:59.945Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}