justauth/JustAuth · error · AuthException
object.get("error") + ":" + object.get("error_description")
Error message
object.get("error") + ":" + object.get("error_description") What it means
AuthQqRequest.getOpenId throws AuthException built from 'error:error_description' when QQ's /oauth2.0/me endpoint (response stripped of the JSONP callback wrapper) contains an error key. This endpoint exchanges an access token for openid/unionid.
Source
Thrown at src/main/java/me/zhyd/oauth/request/AuthQqRequest.java:91
/**
* 获取QQ用户的OpenId,支持自定义是否启用查询unionid的功能,如果启用查询unionid的功能,
* 那就需要开发者先通过邮件申请unionid功能,参考链接 {@see http://wiki.connect.qq.com/unionid%E4%BB%8B%E7%BB%8D}
*
* @param authToken 通过{@link AuthQqRequest#getAccessToken(AuthCallback)}获取到的{@code authToken}
* @return openId
*/
private String getOpenId(AuthToken authToken) {
String response = new HttpUtils(config.getHttpConfig()).get(UrlBuilder.fromBaseUrl("https://graph.qq.com/oauth2.0/me")
.queryParam("access_token", authToken.getAccessToken())
.queryParam("unionid", config.isUnionId() ? 1 : 0)
.build()).getBody();
String removePrefix = response.replace("callback(", "");
String removeSuffix = removePrefix.replace(");", "");
String openId = removeSuffix.trim();
JSONObject object = JSONObject.parseObject(openId);
if (object.containsKey("error")) {
throw new AuthException(object.get("error") + ":" + object.get("error_description"));
}
authToken.setOpenId(object.getString("openid"));
if (object.containsKey("unionid")) {
authToken.setUnionId(object.getString("unionid"));
}
return StringUtils.isEmpty(authToken.getUnionId()) ? authToken.getOpenId() : authToken.getUnionId();
}
/**
* 返回获取userInfo的url
*
* @param authToken 用户授权token
* @return 返回获取userInfo的url
*/
@Override
protected String userInfoUrl(AuthToken authToken) {
return UrlBuilder.fromBaseUrl(source.userInfo())
.queryParam("access_token", authToken.getAccessToken())View on GitHub (pinned to 694bbf1b01)
Solutions
- Refresh the access token before calling getOpenId; QQ access tokens expire per expires_in returned at token time
- Confirm config.getClientId() is the same QQ Connect appid under which the token was issued
- Catch AuthException and inspect the error/error_description pair (e.g. 100016) to decide refresh vs re-login
- Persist the openid/unionid after first retrieval to avoid repeated me-endpoint calls
Example fix
null
Defensive patterns
Strategy: retry
Validate before calling
null
Type guard
null
Try / catch
try {
String openId = qqRequest.getOpenId(token); // via getUserInfo path
} catch (AuthException e) {
if (String.valueOf(e.getMessage()).contains("100016")) {
token = qqRequest.refresh(token).getData();
// retry once
}
} Prevention
- Persist openid/unionid after first login to skip repeated me calls
- Ensure the appid used for token issuance matches config.getClientId()
- Refresh tokens proactively; QQ access tokens expire quickly
When it happens
Trigger: getUserInfo or getOpenId running with an access token QQ has expired or invalidated (error 100016 invalid access token), or a malformed token passed in.
Common situations: Stored QQ token reused after expiry, token from a different QQ Connect app (appid mismatch with oauth_consumer_key), or the JSONP-stripping replace failing because QQ changed the callback format.
Related errors
- object.getString("msg")
- object.getString("m")
- userProfile.getString("description")
- accessTokenObject.get("msg")
- object.getString("error_description") / object.getString("er
AI-assisted analysis of justauth/JustAuth@694bbf1b01 (2026-08-14).
Data as JSON: /api/errors/0d03cd912f6634a2.
Report an issue: GitHub.