{"record":{"id":"51c360f866c839dc","repo":"jeecgboot/JeecgBoot","slug":"error-51c360","errorCode":null,"errorMessage":"该敲敲云账号已被其它第三方账号绑定,请解绑或绑定其它敲敲云账号","messagePattern":"该敲敲云账号已被其它第三方账号绑定,请解绑或绑定其它敲敲云账号","errorType":"exception","errorClass":"JeecgBootException","httpStatus":null,"severity":"error","filePath":"jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysThirdAccountServiceImpl.java","lineNumber":214,"sourceCode":"        super.save(user);\n        return user;\n    }\n\n    @Override\n    public SysThirdAccount bindThirdAppAccountByUserId(SysThirdAccount sysThirdAccount) {\n        String thirdUserUuid = sysThirdAccount.getThirdUserUuid();\n        String thirdType = sysThirdAccount.getThirdType();\n        //获取当前登录用户\n        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();\n        //当前第三方用户已被其他用户所绑定\n        SysThirdAccount oneByThirdUserId = this.getOneByUuidAndThirdType(thirdUserUuid, thirdType,CommonConstant.TENANT_ID_DEFAULT_VALUE, null);\n        if(null != oneByThirdUserId){\n            //如果不为空，并且第三方表和当前登录的用户一致，直接返回\n            if(oConvertUtils.isNotEmpty(oneByThirdUserId.getSysUserId()) && oneByThirdUserId.getSysUserId().equals(sysUser.getId())){\n                return oneByThirdUserId;\n            }else if(oConvertUtils.isNotEmpty(oneByThirdUserId.getSysUserId())){\n                //如果第三方表的用户id不为空，那就说明已经绑定过了\n                throw new JeecgBootException(\"该敲敲云账号已被其它第三方账号绑定,请解绑或绑定其它敲敲云账号\");\n            }else{\n                //更新第三方表信息用户id\n                oneByThirdUserId.setSysUserId(sysUser.getId());\n                oneByThirdUserId.setThirdType(thirdType);\n                sysThirdAccountMapper.updateById(oneByThirdUserId);\n                return oneByThirdUserId;\n            }\n        }else{\n            throw new JeecgBootException(\"账号绑定失败,请稍后重试\");\n        }\n    }\n\n    @Override\n    public SysThirdAccount getOneByUuidAndThirdType(String unionid, String thirdType,Integer tenantId,String thirdUserId) {\n        LambdaQueryWrapper<SysThirdAccount> queryWrapper = new LambdaQueryWrapper<>();\n        queryWrapper.eq(SysThirdAccount::getThirdType, thirdType);\n        // 代码逻辑说明: 如果第三方用户id为空那么就不走第三方用户查询逻辑，因为扫码登录third_user_id是唯一的，没有重复的情况---\n        if(oConvertUtils.isNotEmpty(thirdUserId)){","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/jeecgboot/JeecgBoot/blob/96fb33f5ec68516da0b0147da06b2eb0419e063a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysThirdAccountServiceImpl.java#L196-L232","documentation":"Thrown by SysThirdAccountServiceImpl when binding a third-party account. It looks up the existing third-account row by thirdUserUuid+thirdType; if that row already has a non-empty sysUserId that does not equal the current login user's id, the binding is rejected because the third-party identity is already claimed by another system user.","triggerScenarios":"A user attempts to bind a third-party identity (WeChat/QQ/etc.) whose sys_third_account row already has a sysUserId belonging to a different QQYun user.","commonSituations":"User previously bound the same WeChat unionid under a different account and tries to rebind without unbinding; the third-user-uuid collided due to provider data issue; a prior bind left a stale sysUserId. Also multi-tenant default-tenant lookup returns a row bound in another context, or tenant filter is null so the wrong row is matched.","solutions":["Have the original account unbind the third-party identity first, then retry.","If the binding is erroneous (stale data), clear sysUserId on the sys_third_account row for this thirdUserUuid+thirdType.","Verify the correct thirdType and thirdUserUuid are being passed so the lookup matches the intended row.","Bind a different QQYun account instead, as the message suggests."],"exampleFix":"// before\nthirdAccountService.bindThirdAccount(sysThirdAccount); // throws - already bound\n\n// after: unbind first, then bind\nsysThirdAccountMapper.clearSysUserId(thirdUserUuid, thirdType);\nthirdAccountService.bindThirdAccount(sysThirdAccount);","handlingStrategy":"validation","validationCode":"SysThirdAccount row = thirdAccountService.getOneByUuidAndThirdType(\n    uuid, thirdType, CommonConstant.TENANT_ID_DEFAULT_VALUE, null);\nif (row != null && oConvertUtils.isNotEmpty(row.getSysUserId())\n    && !row.getSysUserId().equals(currentUser.getId())) {\n    return Result.error(\"该第三方账号已被绑定，请先解绑\");\n}","typeGuard":"boolean isFreeToBind(SysThirdAccount row, LoginUser me) {\n  return row != null && (oConvertUtils.isEmpty(row.getSysUserId())\n      || row.getSysUserId().equals(me.getId()));\n}","tryCatchPattern":"try { thirdAccountService.bindThirdAccount(acct); }\ncatch (JeecgBootException e) {\n  if (e.getMessage().contains(\"已被其它\")) return Result.error(\"请先解绑原账号\");\n  throw e;\n}","preventionTips":["Provide an explicit unbind action in the UI.","Pre-check the third-account row's sysUserId before bind.","Handle the 'already bound to me' case as success."],"tags":["authentication","third-party-binding","oauth","account"],"backgroundTag":null,"analyzedSha":"96fb33f5ec68516da0b0147da06b2eb0419e063a","analyzedAt":"2026-08-14T00:04:16.786Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}