{"record":{"id":"325067bccc60b8e8","repo":"iflytek/astron-agent","slug":"model-api-key-not-found-businessexception-responseenum","errorCode":"MODEL_API_KEY_NOT_FOUND","errorMessage":"BusinessException(ResponseEnum.MODEL_API_KEY_NOT_FOUND)","messagePattern":"BusinessException\\(ResponseEnum\\.MODEL_API_KEY_NOT_FOUND\\)","errorType":"error_code","errorClass":"BusinessException","httpStatus":null,"severity":"critical","filePath":"console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/model/ModelService.java","lineNumber":186,"sourceCode":"            log.error(\"Model validation failed, url={}, err={}\", url, e.getMessage(), e);\n            throw e;\n        } catch (HttpClientErrorException | HttpServerErrorException e) {\n            log.error(\"Model interface call failed, url={}, http={}, body={}\", url, e.getStatusCode(), e.getResponseBodyAsString(), e);\n            throw new BusinessException(ResponseEnum.MODEL_APIKEY_ERROR);\n        } catch (Exception e) {\n            log.error(\"Model validation failed, url={}, err={}\", url, e.getMessage(), e);\n            throw new BusinessException(ResponseEnum.MODEL_CHECK_FAILED);\n        }\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\");","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/model/ModelService.java#L168-L204","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"-- before: row missing/invalid\nSELECT * FROM config_info WHERE category='MODEL_SECRET_KEY' AND code='private_key' AND is_valid=1; -- 0 rows\n-- after\nINSERT INTO config_info (category, code, value, is_valid) VALUES ('MODEL_SECRET_KEY','private_key','-----BEGIN RSA PRIVATE KEY-----...',1);","handlingStrategy":"validation","validationCode":"ConfigInfo key = configInfoMapper.selectOne(new LambdaQueryWrapper<ConfigInfo>()\n    .eq(ConfigInfo::getCategory, \"MODEL_SECRET_KEY\")\n    .eq(ConfigInfo::getCode, \"private_key\")\n    .eq(ConfigInfo::getIsValid, 1));\nif (key == null) throw new IllegalStateException(\"MODEL_SECRET_KEY/private_key config missing; seed config_info before accepting model registrations\");","typeGuard":"boolean rsaKeyConfigPresent() { return configInfoMapper.selectCount(new LambdaQueryWrapper<ConfigInfo>().eq(ConfigInfo::getCategory,\"MODEL_SECRET_KEY\").eq(ConfigInfo::getCode,\"private_key\").eq(ConfigInfo::getIsValid,1)) > 0; }","tryCatchPattern":"try { modelService.validateModel(req); } catch (BusinessException e) { if (ResponseEnum.MODEL_API_KEY_NOT_FOUND.equals(e.getResponseEnum())) { alertOpsToSeedConfig(); return 503-config-missing; } throw e; }","preventionTips":["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"],"tags":["configuration","missing-config","rsa","database"],"backgroundTag":"missing-config-value","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"}