apache/shenyu · error · ShenyuException

parameter error

Error message

parameter error

What it means

AiProxyApiKeyServiceImpl.create() validates the incoming ProxyApiKeyDTO before inserting an AI proxy API key record. When the DTO carries no namespaceId (namespace blank), ShenyuResultMessage.PARAMETER_ERROR is thrown as a ShenyuException, aborting the transaction. The namespace is mandatory because keys are scoped per namespace in ShenYu's multi-tenant model.

Solutions

  1. Add a non-blank namespaceId to the request DTO before calling create/createOrUpdate.
  2. In the dashboard/form, ensure the namespace selector value is bound and not empty on submit.
  3. Server-side: pre-validate dto.getNamespaceId() and return a 400 with a clearer field-specific message instead of the generic PARAMETER_ERROR.

Example fix

// before
{"proxyApiKey":"my-key"}
// after
{"proxyApiKey":"my-key","namespaceId":"649330b6-1106-4a1f-8f9c-c292a62d2fda"}
Defensive patterns

Strategy: validation

Validate before calling

if (dto == null || dto.getNamespaceId() == null || dto.getNamespaceId().isBlank()) {
    throw new IllegalArgumentException("namespaceId is required to create an AI proxy API key");
}
apiKeyService.createOrUpdate(dto, selectorId);

Type guard

boolean hasNamespace(ProxyApiKeyDTO dto) {
    return dto != null && StringUtils.isNotBlank(dto.getNamespaceId());
}

Try / catch

try {
    apiKeyService.createOrUpdate(dto, selectorId);
} catch (ShenyuException e) {
    if (ShenyuResultMessage.PARAMETER_ERROR.equals(e.getMessage())) {
        // 400: namespaceId missing in payload
    }
    throw e;
}

Prevention

When it happens

Trigger: POSTing/PUTing an AI proxy API key whose JSON body omits namespaceId (or sends it as null/empty string); a client DTO deserialized from a partial payload; a dashboard form that fails to include the namespace field. Reached via createOrUpdate when the record is new (no id).

Common situations: Dashboard or scripts calling /ai-proxy-key endpoints with hand-written payloads; API consumers upgrading to the multi-namespace version of ShenYu without updating payloads; copy-pasted curl commands missing namespaceId.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12). Data as JSON: /api/errors/82d442ed21844b31. Report an issue: GitHub.

Appendix: source

Thrown at shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/AiProxyApiKeyServiceImpl.java:88

            final AiProxyRealKeyResolver realKeyResolver) {
        this.mapper = mapper;
        this.eventPublisher = eventPublisher;
        this.realKeyResolver = realKeyResolver;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int create(final ProxyApiKeyDTO dto, final String selectorId) {
        final ProxyApiKeyDO entity = ProxyApiKeyTransfer.INSTANCE.mapToEntity(dto);
        if (StringUtils.isBlank(entity.getId())) {
            entity.setId(UUIDUtils.getInstance().generateShortUuid());
        }
        if (StringUtils.isBlank(entity.getProxyApiKey())) {
            entity.setProxyApiKey(SignUtils.generateKey());
        }
        // validate namespace
        if (StringUtils.isBlank(entity.getNamespaceId())) {
            throw new ShenyuException(ShenyuResultMessage.PARAMETER_ERROR);
        }
        // validate selector id
        if (StringUtils.isBlank(selectorId)) {
            throw new ShenyuException(ShenyuResultMessage.PARAMETER_ERROR);
        }
        entity.setSelectorId(selectorId);
        // unique check for proxyApiKey if provided
        if (StringUtils.isNotBlank(entity.getProxyApiKey())
                && Boolean.TRUE.equals(mapper.proxyApiKeyExisted(selectorId, entity.getProxyApiKey()))) {
            throw new ShenyuException(ShenyuResultMessage.UNIQUE_INDEX_CONFLICT_ERROR);
        }
        if (Objects.isNull(entity.getEnabled())) {
            entity.setEnabled(Boolean.TRUE);
        }
        // back fill generated fields to response dto first
        dto.setId(entity.getId());
        dto.setProxyApiKey(entity.getProxyApiKey());
        dto.setEnabled(entity.getEnabled());

View on GitHub (pinned to 567142e072)