{"record":{"id":"5d503f61d63f15d5","repo":"iflytek/astron-agent","slug":"model-apikey-load-error-businessexception-responseenum","errorCode":"MODEL_APIKEY_LOAD_ERROR","errorMessage":"BusinessException(ResponseEnum.MODEL_APIKEY_LOAD_ERROR)","messagePattern":"BusinessException\\(ResponseEnum\\.MODEL_APIKEY_LOAD_ERROR\\)","errorType":"error_code","errorClass":"BusinessException","httpStatus":null,"severity":"error","filePath":"console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/model/ModelService.java","lineNumber":194,"sourceCode":"        }\n    }\n\n\n    private String decryptApiKey(String apiKey) {\n        ConfigInfo modelSecretKey = configInfoMapper.selectOne(Wrappers.<ConfigInfo>lambdaQuery()\n                .eq(ConfigInfo::getCategory, \"MODEL_SECRET_KEY\")\n                .eq(ConfigInfo::getCode, \"private_key\")\n                .eq(ConfigInfo::getIsValid, 1));\n        if (modelSecretKey == null) {\n            throw new BusinessException(ResponseEnum.MODEL_API_KEY_NOT_FOUND);\n        }\n\n        try {\n            RSAPrivateKey privateKey = RSAUtil.loadPrivateKey(modelSecretKey.getValue());\n            return RSAUtil.decryptByPrivateKeyBase64(apiKey, privateKey);\n        } catch (Exception e) {\n            log.error(\"Decrypt API Key failed\", e);\n            throw new BusinessException(ResponseEnum.MODEL_APIKEY_LOAD_ERROR);\n        }\n    }\n\n    private Map<String, Object> buildValidationPayload(String modelDomain, String provider) {\n        if (PROVIDER_GOOGLE.equals(provider)) {\n            Map<String, Object> textPart = new HashMap<>();\n            textPart.put(\"text\", \"Hello!\");\n\n            Map<String, Object> content = new HashMap<>();\n            content.put(\"role\", \"user\");\n            content.put(\"parts\", Collections.singletonList(textPart));\n\n            Map<String, Object> generationConfig = new HashMap<>();\n            generationConfig.put(\"maxOutputTokens\", 16);\n\n            Map<String, Object> payload = new HashMap<>();\n            payload.put(\"contents\", Collections.singletonList(content));\n            payload.put(\"generationConfig\", generationConfig);","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/model/ModelService.java#L176-L212","documentation":"MODEL_APIKEY_LOAD_ERROR is thrown by ModelService.decryptApiKey when the stored model API key cannot be decrypted. The service loads an RSA private key from the model secret key config and decrypts the Base64-encoded API key; any exception in loadPrivateKey or decryptByPrivateKeyBase64 (malformed PEM, wrong key, corrupt ciphertext) is wrapped in this BusinessException.","triggerScenarios":"validateModel calls decryptApiKey and the RSA private key stored in the modelSecretKey config value is invalid, not valid PEM, or the apiKey ciphertext was not encrypted with (or cannot be decrypted by) that key; Base64 decoding of the apiKey also fails.","commonSituations":"Secret-key config row missing or truncated after a DB migration/import; API key encrypted with a different keypair after rotating keys; copy-pasted key lost padding or newlines; environment (modelSecretKey) pointing to a stale value.","solutions":["Verify the modelSecretKey config value contains a complete, valid RSA private key PEM (correct BEGIN/END markers, no truncation).","Re-save/re-encrypt the model API key so it was encrypted with the current private key, then retry validation.","Check server logs for the underlying 'Decrypt API Key failed' stack trace to distinguish key-load vs decrypt failure.","Ensure RSAUtil's expected key format (PKCS#8 vs PKCS#1) matches what is stored; convert the key if needed.","Confirm the apiKey field stored for the model is valid Base64 with no whitespace or characters lost in transit."],"exampleFix":"// before: storing a key encrypted with an old/rotated keypair\napiKey = encryptWithOldPublicKey(rawKey); // decrypt fails at runtime\n// after: re-encrypt with the current keypair before saving\napiKey = RSAUtil.encryptByPublicKeyBase64(rawKey, RSAUtil.loadPublicKey(currentPublicKey));","handlingStrategy":"validation","validationCode":"boolean keyUsable = modelSecretKey != null && modelSecretKey.contains(\"BEGIN\") && modelSecretKey.contains(\"END\") && isBase64(apiKey);\nif (!keyUsable) { fixCredentialsBeforeValidate(); }","typeGuard":"boolean isValidPem(String s) { return s != null && s.strip().startsWith(\"-----BEGIN\") && s.strip().endsWith(\"-----\") && !s.isBlank(); }","tryCatchPattern":"try { validateModel(req); } catch (BusinessException e) { if (\"MODEL_APIKEY_LOAD_ERROR\".equals(e.getCode())) { reencryptAndResaveApiKey(); } throw e; }","preventionTips":["Store keys as complete PKCS#8 PEM and validate the format on save.","Re-encrypt stored API keys whenever the keypair rotates.","Never hand-edit secret config rows; use the save API so encryption is applied consistently.","Keep apiKey values strict Base64 (no whitespace) end to end."],"tags":["encryption","rsa","api-key","config"],"backgroundTag":"missing-credentials","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}