iflytek/astron-agent · error · BusinessException

UNAUTHORIZED

UNAUTHORIZED

Error message

BusinessException(ResponseEnum.UNAUTHORIZED)

What it means

UNAUTHORIZED is thrown by getRuntimeModelDetail when the currently authenticated user's uid does not match the authenticatedUid argument passed by the caller. This is an explicit identity-consistency check at the start of the method: the runtime model detail endpoint may only be read by the same user whose authentication context was verified upstream.

Solutions

  1. Ensure the caller passes the uid taken from the same authenticated security context (UserInfoManagerHandler.get().getUid()), not a client-supplied value.
  2. Re-authenticate: refresh the token/session so the security context and forwarded uid match.
  3. Fix the upstream call site to derive authenticatedUid from the current request's auth filter rather than trusting request headers/body.
  4. Check auth filter/ordering so UserInfoManagerHandler is populated before this method runs.

Example fix

// before
llmInfoVo = modelService.getRuntimeModelDetail(modelId, request.getHeader("uid"), spaceId); // spoofable
// after
String uid = UserInfoManagerHandler.get().getUid();
llmInfoVo = modelService.getRuntimeModelDetail(modelId, uid, spaceId);
Defensive patterns

Strategy: type-guard

Validate before calling

if (!Objects.equals(UserInfoManagerHandler.get().getUid(), authenticatedUid)) { throw new SecurityException("uid mismatch before calling getRuntimeModelDetail"); }

Type guard

boolean sameIdentity(String authenticatedUid) { UserInfo u = UserInfoManagerHandler.get(); return u != null && Objects.equals(u.getUid(), authenticatedUid); }

Try / catch

try { return modelService.getRuntimeModelDetail(modelId, authenticatedUid, spaceId); } catch (BusinessException e) { if ("UNAUTHORIZED".equals(e.getCode())) { forceReauth(); } throw e; }

Prevention

When it happens

Trigger: Calling getRuntimeModelDetail (public entry, e.g. from a chat/runtime controller) where the UserInfoManagerHandler thread-local user differs from the authenticatedUid parameter — e.g. forged/missing auth context, admin-tooling calling with another user's uid, or a token/session mismatch after re-login.

Common situations: Expired or replaced JWT while an old cached uid is passed along; service-to-service calls forwarding a different uid header than the one in the security context; developer tools invoking the method with a hardcoded uid.

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/1c784f7b74f871af. Report an issue: GitHub.

Appendix: source

Thrown at console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/model/ModelService.java:934

            String currentUid = userInfo.getUid();
            Long currentSpaceId = SpaceInfoUtil.getSpaceId(); // Assuming this gets current space

            Model model = findAccessibleModel(modelId, currentUid, currentSpaceId);
            if (model == null) {
                // Model doesn't exist or user doesn't have access to it
                return ApiResult.error(ResponseEnum.MODEL_NOT_EXIST);
            }

            LLMInfoVo modelVo = buildPublicLLMInfoVoFromModel(model, userInfo);
            return ApiResult.success(modelVo);
        }
    }

    public LLMInfoVo getRuntimeModelDetail(Long modelId, String authenticatedUid, Long authorizedSpaceId) {
        UserInfo userInfo = UserInfoManagerHandler.get();
        if (!Objects.equals(userInfo.getUid(), authenticatedUid)) {
            throw new BusinessException(ResponseEnum.UNAUTHORIZED);
        }

        Model model = findAccessibleModel(modelId, authenticatedUid, authorizedSpaceId);
        if (model == null) {
            throw new BusinessException(ResponseEnum.MODEL_NOT_EXIST);
        }
        return buildRuntimeLLMInfoVoFromModel(model, userInfo);
    }

    private Model findAccessibleModel(Long modelId, String uid, Long spaceId) {
        if (spaceId != null && enterpriseSpaceService.checkUserBelongSpace(spaceId, uid) == null) {
            return null;
        }

        LambdaQueryWrapper<Model> wrapper = new LambdaQueryWrapper<Model>()
                .eq(Model::getId, modelId)
                .eq(Model::getIsDeleted, 0);
        if (spaceId != null) {

View on GitHub (pinned to 5e758547a8)