{"record":{"id":"389fc03f51f8ebdf","repo":"iflytek/astron-agent","slug":"model-apikey-load-error","errorCode":"MODEL_APIKEY_LOAD_ERROR","errorMessage":"ResponseEnum.MODEL_APIKEY_LOAD_ERROR","messagePattern":"ResponseEnum\\.MODEL_APIKEY_LOAD_ERROR","errorType":"error_code","errorClass":"BusinessException","httpStatus":null,"severity":"error","filePath":"console/backend/hub/src/main/java/com/iflytek/astron/console/hub/service/agentmemory/runtime/AgentMemorySecretService.java","lineNumber":35,"sourceCode":"@RequiredArgsConstructor\npublic class AgentMemorySecretService {\n\n    private static final String CAT_MODEL_SECRET_KEY = \"MODEL_SECRET_KEY\";\n    private static final String CODE_PRIVATE_KEY = \"private_key\";\n    private static final long PRIVATE_KEY_CACHE_TTL_MS = 60_000L;\n\n    private final ConfigInfoMapper configInfoMapper;\n\n    private volatile RSAPrivateKey cachedPrivateKey;\n    private volatile long privateKeyCacheExpiresAt;\n\n    public String decryptApiKey(String apiKeyCiphertext) {\n        RSAPrivateKey privateKey = getPrivateKey();\n        try {\n            return RSAUtil.decryptByPrivateKeyBase64(apiKeyCiphertext, privateKey);\n        } catch (Exception e) {\n            log.error(\"Decrypt agent memory API key failed\", e);\n            throw new BusinessException(ResponseEnum.MODEL_APIKEY_LOAD_ERROR);\n        }\n    }\n\n    private RSAPrivateKey getPrivateKey() {\n        long now = System.currentTimeMillis();\n        RSAPrivateKey privateKey = cachedPrivateKey;\n        if (privateKey != null && now < privateKeyCacheExpiresAt) {\n            return privateKey;\n        }\n        synchronized (this) {\n            now = System.currentTimeMillis();\n            privateKey = cachedPrivateKey;\n            if (privateKey != null && now < privateKeyCacheExpiresAt) {\n                return privateKey;\n            }\n            privateKey = loadPrivateKey();\n            cachedPrivateKey = privateKey;\n            privateKeyCacheExpiresAt = System.currentTimeMillis() + PRIVATE_KEY_CACHE_TTL_MS;","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/backend/hub/src/main/java/com/iflytek/astron/console/hub/service/agentmemory/runtime/AgentMemorySecretService.java#L17-L53","documentation":"AgentMemorySecretService.decryptApiKey wraps RSA decryption of the stored agent-memory API key. Any failure (bad ciphertext, wrong key, malformed Base64) is converted to MODEL_APIKEY_LOAD_ERROR after logging. It means the stored ciphertext could not be decrypted with the configured private key.","triggerScenarios":"Calling any flow that decrypts the memory API key when the stored apiKeyCiphertext is corrupt, was encrypted with a different/wrong public key, is truncated, or is not valid Base64.","commonSituations":"RSA keypair rotated in config_info so old ciphertexts no longer decrypt; ciphertext copy-pasted with whitespace/newlines; data migrated between environments with different private keys.","solutions":["Re-encrypt the API key with the public key matching the current configured private key and save it again via saveConfig.","Verify config_info (category=model secret key, code=private key) holds the correct, unmodified private key.","Check the ciphertext is complete, valid Base64, and not truncated by the DB column size."],"exampleFix":"// before\nString ct = encryptWithOldPublicKey(rawKey); // key since rotated\nconfig.setApiKeyCiphertext(ct);\n// after\nString ct = RSAUtil.encryptByPublicKey(rawKey, currentPublicKey);\nconfig.setApiKeyCiphertext(ct); // decryptable with current private key","handlingStrategy":"try-catch","validationCode":"// ciphertext sanity check before sending\nif (!/^[A-Za-z0-9+/=\\r\\n]+$/.test(ciphertext)) { throw new Error('not valid base64 ciphertext'); }","typeGuard":null,"tryCatchPattern":"try { String key = secretService.decryptApiKey(ct); } catch (BusinessException e) { if (e.getCode() == ResponseEnum.MODEL_APIKEY_LOAD_ERROR) { markKeyAsNeedsReentry(); } }","preventionTips":["Re-encrypt stored keys whenever the RSA keypair is rotated.","Validate ciphertext is full, valid Base64 before persisting.","Keep encryption and decryption keypairs versioned together."],"tags":["crypto","rsa","api-key"],"backgroundTag":"decryption-failed","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"}