iflytek/astron-agent · error · BusinessException
EXCEED_AUTHORITY
EXCEED_AUTHORITY
Error message
BusinessException(ResponseEnum.EXCEED_AUTHORITY)
What it means
Thrown by checkAndDelete after the model is found, when model.getUid() does not equal the uid resolved from the current session (UserInfoManagerHandler.getUserId()). Only the owner may delete a model; anyone else — even a space admin — receives EXCEED_AUTHORITY.
Solutions
- Delete the model as the owning user (log in with or use credentials of model.getUid()).
- Have the owner delete it, or add an explicit admin/transfer flow if delegation is required.
- Verify the auth context (UserInfoManagerHandler) resolves the expected uid — check token/session mismatch.
- Compare stored uid and session uid for format differences (whitespace, case) if ownership looks correct.
Example fix
// before
// deleting with a service account token whose uid != model owner
await deleteModel(modelId);
// after
const model = await getModelDetail(modelId);
if (model.uid !== currentUid) {
throw new Error(`Only owner ${model.uid} can delete model ${modelId}`);
}
await deleteModel(modelId); Defensive patterns
Strategy: validation
Validate before calling
Model m = modelService.getById(modelId); boolean owned = m != null && Objects.equals(m.getUid(), UserInfoManagerHandler.getUserId());
Type guard
if (m == null || m.getUid() == null || !m.getUid().equals(currentUid)) { /* not owner */ } Try / catch
try { return modelService.checkAndDelete(modelId, request); }
catch (BusinessException e) {
if (ResponseEnum.EXCEED_AUTHORITY.equals(e.getResponseEnum())) {
throw new BusinessException(e.getResponseEnum(), "Only the model owner can delete this model");
}
throw e;
} Prevention
- Expose an isOwner flag in list/detail APIs so the UI can hide delete buttons
- Ensure auth tokens and session uid resolve to the same account
- Never assume space admin rights imply delete permission
When it happens
Trigger: Authenticated user A invokes the delete API for a model created by user B; session/uid header resolves to a different account than the one that created the model (e.g. after switching accounts or service-account tokens).
Common situations: Shared test environments where a teammate tries to delete another's model; API tokens belonging to a different user than the UI session; uid stored with different casing/format so equals() fails.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12).
Data as JSON: /api/errors/d3f83c9003070b3d.
Report an issue: GitHub.
Appendix: source
Thrown at console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/model/ModelService.java:1047
ConfigInfo publicKey =
configInfoMapper.selectOne(
new LambdaQueryWrapper<ConfigInfo>()
.eq(ConfigInfo::getCategory, CAT_MODEL_SECRET_KEY)
.eq(ConfigInfo::getCode, CODE_PUBLIC_KEY)
.eq(ConfigInfo::getIsValid, 1));
return Optional.ofNullable(publicKey).map(ConfigInfo::getValue).orElse(null);
}
@Transactional(rollbackFor = Exception.class)
public ApiResult checkAndDelete(Long modelId, HttpServletRequest request) {
String uid = UserInfoManagerHandler.getUserId();
Model model = this.getById(modelId);
if (model == null) {
throw new BusinessException(ResponseEnum.MODEL_NOT_EXIST);
}
if (!model.getUid().equals(uid)) {
log.warn("Unauthorized deletion, uid={}, modelId={}", uid, modelId);
throw new BusinessException(ResponseEnum.EXCEED_AUTHORITY);
}
checkWorkflowReference(uid, model);
Integer modelCount = sparkBotMapper.checkDomainIsUsage(uid, model.getDomain());
if (modelCount != null && modelCount > 0) {
throw new BusinessException(ResponseEnum.MODEL_DELETE_FAILED_APPLY_AGENT);
}
boolean result;
if (Objects.equals(model.getType(), 1)) {
result = this.removeById(modelId);
} else {
result = this.removeById(modelId) && modelHandler.deleteModel(model.getRemark());
}
return ApiResult.success(result);
}
View on GitHub (pinned to 5e758547a8)