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

  1. Set apiKey in the AI proxy plugin configuration to a valid provider credential and re-save/publish.
  2. Verify the secret actually reaches the gateway config store (check what the dashboard saved and what data sync delivered).
  3. Inject the key from a secrets manager/environment template if it is being lost during deployment.
  4. 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

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


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)