alibaba/nacos · error · NacosApiException
20002
20002
Error message
Request header `Request-Module` must be `AI`.
What it means
Stateful Agent HTTP operations (register, deregister, heartbeat) require the 'Request-Module' HTTP header to be exactly 'AI' (case-insensitive). The AgentHttpClientLifecycleService.validateStatefulHeaders method (line 230) throws this NacosApiException (code 20002, INVALID_PARAM) when the header is missing, blank, or set to any other module name. This routes the request to the correct AI module handler.
Source
Thrown at ai/src/main/java/com/alibaba/nacos/ai/service/agent/runtime/AgentHttpClientLifecycleService.java:231
attributes == null ? null : attributes.getClientAttribute(IDENTITY_ATTRIBUTE);
if (!Objects.equals(boundIdentity, VisibilityHelper.resolveCurrentIdentity())) {
throw accessDenied("HTTP Client identity does not match its initial binding.");
}
}
private HttpConnectionBasedClient getClient(String externalClientId) {
String internalClientId =
HttpConnectionBasedClient.getInternalClientId(externalClientId);
Client client = clientManager.getClient(internalClientId);
return client instanceof HttpConnectionBasedClient
? (HttpConnectionBasedClient) client : null;
}
private void validateStatefulHeaders(String externalClientId, String requestModule)
throws NacosApiException {
validateExternalClientId(externalClientId);
if (!Constants.AI.AI_MODULE.equalsIgnoreCase(requestModule)) {
throw new NacosApiException(NacosException.INVALID_PARAM,
ErrorCode.PARAMETER_VALIDATE_ERROR,
"Request header `" + HttpHeaderConsts.REQUEST_MODULE + "` must be `AI`.");
}
}
private void validateExternalClientId(String externalClientId) throws NacosApiException {
if (StringUtils.isBlank(externalClientId)
|| externalClientId.length() > MAX_EXTERNAL_CLIENT_ID_LENGTH
|| !EXTERNAL_CLIENT_ID_PATTERN.matcher(externalClientId).matches()) {
throw new NacosApiException(NacosException.INVALID_PARAM,
ErrorCode.PARAMETER_VALIDATE_ERROR,
"Request header `" + ClientConstants.HTTP_CLIENT_ID_HEADER
+ "` must match `[A-Za-z0-9._:-]+` and contain 1 to 256 characters.");
}
}
private ClientLivenessInfo buildLivenessInfo() {
// These are the effective fixed intervals used by HttpConnectionBasedClientManager.View on GitHub (pinned to 9b989acdf1)
Solutions
- Add the HTTP header 'Request-Module: AI' to every stateful Agent HTTP request.
- If using an SDK, ensure you are using the AI agent client, not the Naming client.
- Verify that no intermediary (load balancer, API gateway) strips the Request-Module header.
Example fix
// before (curl) curl -X POST http://host/v3/admin/ai/agent/endpoints -H 'X-Nacos-Client-Id: my-client' ... // after curl -X POST http://host/v3/admin/ai/agent/endpoints -H 'X-Nacos-Client-Id: my-client' -H 'Request-Module: AI' ...
Defensive patterns
Strategy: validation
Validate before calling
if (!"AI".equalsIgnoreCase(requestModule)) {
throw new IllegalArgumentException("Request-Module header must be AI");
} Type guard
public static boolean isValidAiRequestModule(String header) {
return "AI".equalsIgnoreCase(header);
} Try / catch
try {
service.register(clientId, requestModule, batch);
} catch (NacosApiException e) {
if (e.getErrCode() == 20002 && e.getMessage().contains("Request-Module")) {
// set the header to AI and retry
}
throw e;
} Prevention
- Always include the header 'Request-Module: AI' in every stateful Agent HTTP request.
- Use the official AI agent SDK which sets this header automatically.
- Configure API gateways to preserve the Request-Module header.
When it happens
Trigger: Sending an HTTP request to an Agent endpoint registration/deregistration/heartbeat API without the 'Request-Module: AI' header, or with it set to 'Naming', 'Config', or another value.
Common situations: SDK or curl command that omits the header; a proxy or gateway that strips custom headers; using a Naming client instead of the AI agent client; header name typo (e.g. 'RequestModule' without the hyphen).
Related errors
AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14).
Data as JSON: /api/errors/a371bb5a37be94b0.
Report an issue: GitHub.