iflytek/astron-agent · error · BusinessException

UNAUTHORIZED

UNAUTHORIZED

Error message

BusinessException(ResponseEnum.UNAUTHORIZED)

What it means

SkillSandboxConfigService.getRuntimeCredential validates the internal service token before issuing sandbox runtime credentials (provider, API key, timeout, internet flag). If no runtimeCredentialTokenProvider is configured or the presented serviceToken does not match, it throws UNAUTHORIZED. This is the service-to-service authentication gate for the sandbox runtime.

Solutions

  1. Ensure the sandbox runtime sends the exact configured service token header.
  2. Confirm the same token value is configured in both the toolkit service and the sandbox runtime (env var / config).
  3. Restart both services after rotating the token so in-memory providers pick up the new value.
  4. If the feature was just added, verify the runtimeCredentialTokenProvider bean is actually created and injected.

Example fix

// before
http.post("/skill-sandbox/credential", body); // no token header
// after
http.post("/skill-sandbox/credential", body,
    Map.of("X-Service-Token", configuredServiceToken));
Defensive patterns

Strategy: validation

Validate before calling

if (serviceToken == null || !serviceToken.equals(expectedToken)) {
    throw new IllegalArgumentException("service token missing or mismatched");
}

Try / catch

try {
    cred = runtimeClient.getCredential(token, flowId, uid, spaceId);
} catch (BusinessException e) {
    if ("UNAUTHORIZED".equals(e.getCode())) rotateAndRetryWithFreshToken();
}

Prevention

When it happens

Trigger: Calling getRuntimeCredential (or its REST endpoint) with a null/missing/incorrect serviceToken, or with the runtime credential feature disabled so runtimeCredentialTokenProvider is null.

Common situations: Sandbox runtime calling with a stale or rotated token after redeployment; token env var not set on one side (provider never configured); caller omitting the Authorization/service-token header entirely.

Understand the failure class

Related errors


AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12). Data as JSON: /api/errors/ef9b1a66f0a97bf2. Report an issue: GitHub.

Appendix: source

Thrown at console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/skill/SkillSandboxConfigService.java:133

        SkillSandboxConfig config = getActiveConfig(uid, spaceId);
        SkillSandboxRuntimeRefDto dto = new SkillSandboxRuntimeRefDto();
        dto.setProvider(PROVIDER_E2B);
        dto.setEnabled(config != null);
        dto.setUid(uid);
        dto.setSpaceId(spaceId);
        return dto;
    }

    /**
     * Resolve the E2B credential only for the authenticated private broker. A workflow reference
     * derives scope from the database; standalone agent calls must provide a currently authorized
     * uid/space pair.
     */
    public SkillSandboxRuntimeCredentialDto getRuntimeCredential(
            String serviceToken, String flowId, String uid, Long spaceId) {
        if (runtimeCredentialTokenProvider == null
                || !runtimeCredentialTokenProvider.matches(serviceToken)) {
            throw new BusinessException(ResponseEnum.UNAUTHORIZED);
        }
        assertExplicitScope(uid, spaceId);
        SkillSandboxConfig config;
        if (StringUtils.isNotBlank(flowId)) {
            List<Workflow> workflows = workflowMapper.selectList(
                    Wrappers.lambdaQuery(Workflow.class)
                            .eq(Workflow::getFlowId, StringUtils.trim(flowId))
                            .eq(Workflow::getDeleted, Boolean.FALSE)
                            .last("limit 2"));
            if (workflows == null || workflows.size() != 1) {
                throw new BusinessException(ResponseEnum.WORKFLOW_NOT_EXIST);
            }
            Workflow workflow = workflows.getFirst();
            assertWorkflowExecutionScope(workflow, uid, spaceId);
            config = getActiveConfigForTrustedScope(workflow.getUid(), workflow.getSpaceId());
        } else {
            config = getActiveConfigForTrustedScope(uid, spaceId);
        }

View on GitHub (pinned to 5e758547a8)