apache/shenyu · error · IllegalArgumentException
apiKey must not be empty
Error message
apiKey must not be empty
What it means
createOpenAiApi in AiProxyPlugin also requires a non-null, non-empty apiKey to authenticate with the AI provider. If the key is absent the plugin throws IllegalArgumentException before building the OpenAiApi client.
Solutions
- Set apiKey in the AI proxy plugin configuration to a valid provider credential and re-save/publish.
- Verify the secret actually reaches the gateway config store (check what the dashboard saved and what data sync delivered).
- Inject the key from a secrets manager/environment template if it is being lost during deployment.
- Validate both primary and fallback AiCommonConfig, since resolveFallbackContext uses a separate config object.
Example fix
// before
{"baseUrl":"https://api.openai.com"} // apiKey missing
// after
{"baseUrl":"https://api.openai.com","apiKey":"${OPENAI_API_KEY}"} Defensive patterns
Strategy: validation
Validate before calling
function validateAiConfig(cfg) {
if (!cfg || typeof cfg.apiKey !== 'string' || cfg.apiKey.trim() === '') {
throw new Error('AI proxy config: apiKey must not be empty');
}
} Type guard
function hasApiKey(cfg) {
return typeof cfg?.apiKey === 'string' && cfg.apiKey.trim().length > 0;
} Try / catch
try {
OpenAiApi api = plugin.createOpenAiApi(config);
} catch (IllegalArgumentException e) {
log.error("AI apiKey missing", e);
return ResponseEntity.status(503).body("AI proxy not configured");
} Prevention
- Inject the API key from a secrets manager rather than hand-editing config.
- Verify secret presence in CI before deploying gateway config.
- Keep primary and fallback AiCommonConfig both populated.
When it happens
Trigger: AiCommonConfig.apiKey is null or empty when createOpenAiApi runs (initial client cache build via getCachedOpenAiApi, or fallback client creation via resolveFallbackContext).
Common situations: Admin config saved without the API key, secret stripped by a templating/deployment pipeline, key rotated and removed from config, or a different environment (staging) lacking the credential.
Understand the failure class
Background: "API key is required" / "API key not found" / "No API key was set": the missing-api-key error family across 16 libraries — this error's family across 16 libraries.
Related errors
- baseUrl must not be empty
- shenyu.jwt.secretKey is not configured. In a multi-instance…
- shenyu discovery mode current didn't support
- websocket on client open failed, namespaceId is null
- websocket sync token is not configured
AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12).
Data as JSON: /api/errors/35048eb1f88fba63.
Report an issue: GitHub.
Appendix: source
Thrown at shenyu-plugin/shenyu-plugin-ai/shenyu-plugin-ai-proxy/src/main/java/org/apache/shenyu/plugin/ai/proxy/enhanced/AiProxyPlugin.java:248
return OpenAiApiCache.getInstance().computeIfAbsent(cacheKey, () -> createOpenAiApi(config));
}
private int generateConfigCacheKey(final AiCommonConfig config) {
return Objects.hash(
config.getBaseUrl(),
config.getApiKey(),
config.getModel(),
config.getTemperature(),
config.getMaxTokens()
);
}
private OpenAiApi createOpenAiApi(final AiCommonConfig config) {
if (Objects.isNull(config.getBaseUrl()) || config.getBaseUrl().isEmpty()) {
throw new IllegalArgumentException("baseUrl must not be empty");
}
if (Objects.isNull(config.getApiKey()) || config.getApiKey().isEmpty()) {
throw new IllegalArgumentException("apiKey must not be empty");
}
return OpenAiApi.builder()
.baseUrl(config.getBaseUrl())
.apiKey(config.getApiKey())
.build();
}
@Override
public int getOrder() {
return PluginEnum.AI_PROXY.getCode();
}
@Override
public String named() {
return PluginEnum.AI_PROXY.getName();
}
private void logUpstreamError(final Throwable e, final String mode) {View on GitHub (pinned to 567142e072)