iflytek/astron-agent · critical · BusinessException
MODEL_API_KEY_NOT_FOUND
MODEL_API_KEY_NOT_FOUND
Error message
BusinessException(ResponseEnum.MODEL_API_KEY_NOT_FOUND)
What it means
decryptApiKey needs the platform RSA private key to decrypt client-submitted API keys. It loads it from the config_info table (category=MODEL_SECRET_KEY, code=private_key, is_valid=1). If no such active config row exists, the service cannot decrypt anything and throws MODEL_API_KEY_NOT_FOUND — this is a server-side configuration problem, not a user input problem.
Solutions
- Insert a valid config row: category='MODEL_SECRET_KEY', code='private_key', is_valid=1, value=the RSA private key used at encryption time
- Verify the backend is connected to the intended database and query config_info to confirm the row exists and is_valid=1
- Re-run the environment's config seeding/migration scripts after fresh deployments or DB restores
- If keys were rotated, ensure the row's value matches the public key that encrypted the client-submitted api keys
Example fix
-- before: row missing/invalid
SELECT * FROM config_info WHERE category='MODEL_SECRET_KEY' AND code='private_key' AND is_valid=1; -- 0 rows
-- after
INSERT INTO config_info (category, code, value, is_valid) VALUES ('MODEL_SECRET_KEY','private_key','-----BEGIN RSA PRIVATE KEY-----...',1); Defensive patterns
Strategy: validation
Validate before calling
ConfigInfo key = configInfoMapper.selectOne(new LambdaQueryWrapper<ConfigInfo>()
.eq(ConfigInfo::getCategory, "MODEL_SECRET_KEY")
.eq(ConfigInfo::getCode, "private_key")
.eq(ConfigInfo::getIsValid, 1));
if (key == null) throw new IllegalStateException("MODEL_SECRET_KEY/private_key config missing; seed config_info before accepting model registrations"); Type guard
boolean rsaKeyConfigPresent() { return configInfoMapper.selectCount(new LambdaQueryWrapper<ConfigInfo>().eq(ConfigInfo::getCategory,"MODEL_SECRET_KEY").eq(ConfigInfo::getCode,"private_key").eq(ConfigInfo::getIsValid,1)) > 0; } Try / catch
try { modelService.validateModel(req); } catch (BusinessException e) { if (ResponseEnum.MODEL_API_KEY_NOT_FOUND.equals(e.getResponseEnum())) { alertOpsToSeedConfig(); return 503-config-missing; } throw e; } Prevention
- Include the MODEL_SECRET_KEY config row in environment provisioning/seeding scripts
- Add a startup health check that fails fast when the private key config is absent
- Keep the key row valid during rotations: insert the new key before invalidating the old one
- Verify the correct database is configured in each environment
When it happens
Trigger: Calling validateModel with a submitted apiKey that must be decrypted (apiKeyMasked false or id null) while the config_info table has no valid MODEL_SECRET_KEY/private_key row: fresh environment never seeded with the key, key row marked invalid, or wrong DB pointed at.
Common situations: New deployments missing the config seed SQL; operators rotating keys by invalidating the old row but failing to insert the new one; environment uses a different database than the one that was provisioned; key category/code renamed.
Understand the failure class
Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.
Related errors
- MODEL_API_KEY_NOT_FOUND
- 8001
- PG_SQL_NODE_EXECUTION_ERROR
- database type is required
- database username is required
AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12).
Data as JSON: /api/errors/325067bccc60b8e8.
Report an issue: GitHub.
Appendix: source
Thrown at console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/model/ModelService.java:186
log.error("Model validation failed, url={}, err={}", url, e.getMessage(), e);
throw e;
} catch (HttpClientErrorException | HttpServerErrorException e) {
log.error("Model interface call failed, url={}, http={}, body={}", url, e.getStatusCode(), e.getResponseBodyAsString(), e);
throw new BusinessException(ResponseEnum.MODEL_APIKEY_ERROR);
} catch (Exception e) {
log.error("Model validation failed, url={}, err={}", url, e.getMessage(), e);
throw new BusinessException(ResponseEnum.MODEL_CHECK_FAILED);
}
}
private String decryptApiKey(String apiKey) {
ConfigInfo modelSecretKey = configInfoMapper.selectOne(Wrappers.<ConfigInfo>lambdaQuery()
.eq(ConfigInfo::getCategory, "MODEL_SECRET_KEY")
.eq(ConfigInfo::getCode, "private_key")
.eq(ConfigInfo::getIsValid, 1));
if (modelSecretKey == null) {
throw new BusinessException(ResponseEnum.MODEL_API_KEY_NOT_FOUND);
}
try {
RSAPrivateKey privateKey = RSAUtil.loadPrivateKey(modelSecretKey.getValue());
return RSAUtil.decryptByPrivateKeyBase64(apiKey, privateKey);
} catch (Exception e) {
log.error("Decrypt API Key failed", e);
throw new BusinessException(ResponseEnum.MODEL_APIKEY_LOAD_ERROR);
}
}
private Map<String, Object> buildValidationPayload(String modelDomain, String provider) {
if (PROVIDER_GOOGLE.equals(provider)) {
Map<String, Object> textPart = new HashMap<>();
textPart.put("text", "Hello!");
Map<String, Object> content = new HashMap<>();
content.put("role", "user");View on GitHub (pinned to 5e758547a8)