iflytek/astron-agent · error · BusinessException

MODEL_NOT_COMPATIBLE_OPENAI

MODEL_NOT_COMPATIBLE_OPENAI

Error message

BusinessException(ResponseEnum.MODEL_NOT_COMPATIBLE_OPENAI)

What it means

validateModel probes the model endpoint with an OpenAI-compatible request to prove the model works before saving. If the HTTP call completes but the response does not match the accepted OpenAI-compatible shape (and the request was not a pure validation that already saved), the service concludes the endpoint is not OpenAI-compatible and throws MODEL_NOT_COMPATIBLE_OPENAI.

Solutions

  1. Verify the endpoint implements the OpenAI chat/completions response schema (choices[].message.content etc.) — test with curl against the same path the service calls
  2. Check the endpoint URL and path (e.g. /v1/chat/completions) are correct and not hitting an HTML root
  3. Inspect the actual response body logged at validation time to see how it deviates
  4. Use an OpenAI-compatible serving stack (or enable its OpenAI-compatible API mode) for the model

Example fix

// before
endpoint: https://llm.internal/  // returns HTML, not OpenAI schema
// after
endpoint: https://llm.internal/v1  // proxies to OpenAI-compatible /chat/completions
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check OpenAI compatibility before registering
ResponseEntity<String> r = rest.postForEntity(endpoint + "/chat/completions", openAiProbeRequest(), String.class);
if (!r.getStatusCode().is2xxSuccessful() || !r.getBody().contains("\"choices\"")) throw new IllegalStateException("endpoint not OpenAI-compatible");

Type guard

boolean looksOpenAiCompatible(String body) { return body != null && body.trim().startsWith("{") && body.contains("\"choices\"") && body.contains("\"message\""); }

Try / catch

try { modelService.validateModel(req); } catch (BusinessException e) { if (ResponseEnum.MODEL_NOT_COMPATIBLE_OPENAI.equals(e.getResponseEnum())) { log.error("endpoint {} not OpenAI-compatible; inspect response schema", req.getEndpoint()); return 422-incompatible-endpoint; } throw e; }

Prevention

When it happens

Trigger: Registering a model whose endpoint answers 200 OK but returns a non-OpenAI response body (different JSON schema, HTML error page, empty body), or a gateway that silently rewrites responses.

Common situations: Pointing the endpoint at a non-OpenAI-compatible server (e.g. a plain HTTP page, a vendor API with a different schema); proxy/gateway intercepting and returning its own JSON; custom inference servers (vLLM/old builds) with divergent response fields; wrong path appended to the endpoint URL.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12). Data as JSON: /api/errors/f990f0159eb3b612. Report an issue: GitHub.

Appendix: source

Thrown at console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/model/ModelService.java:166

        // 2) Construct/validate URL + request body/headers
        final String provider = normalizeProvider(request.getProvider(), true);
        final String url = buildModelApiUrlNew(request.getEndpoint(), provider, request.getDomain());
        final Map<String, Object> requestBody =
                buildValidationPayload(request.getDomain(), provider);
        final HttpHeaders headers = buildAuthHeaders(decryptedApiKey, provider);

        try {
            String responseBody = doPostModelApi(url, requestBody, headers);
            if (isValidModelResponse(responseBody, provider)) {
                log.info("Model validation passed, domain={}, endpoint={}", request.getDomain(), url);
                request.setApiKey(decryptedApiKey);
                request.setEndpoint(url);
                request.setProvider(provider);
                saveOrUpdateModel(request);
                return "Model validation passed";
            }
            throw new BusinessException(ResponseEnum.MODEL_NOT_COMPATIBLE_OPENAI);
        } catch (BusinessException e) {
            log.error("Model validation failed, url={}, err={}", url, e.getMessage(), e);
            throw e;
        } catch (HttpClientErrorException | HttpServerErrorException e) {
            log.error("Model interface call failed, url={}, http={}, body={}", url, e.getStatusCode(), e.getResponseBodyAsString(), e);
            throw new BusinessException(ResponseEnum.MODEL_APIKEY_ERROR);
        } catch (Exception e) {
            log.error("Model validation failed, url={}, err={}", url, e.getMessage(), e);
            throw new BusinessException(ResponseEnum.MODEL_CHECK_FAILED);
        }
    }


    private String decryptApiKey(String apiKey) {
        ConfigInfo modelSecretKey = configInfoMapper.selectOne(Wrappers.<ConfigInfo>lambdaQuery()
                .eq(ConfigInfo::getCategory, "MODEL_SECRET_KEY")
                .eq(ConfigInfo::getCode, "private_key")
                .eq(ConfigInfo::getIsValid, 1));

View on GitHub (pinned to 5e758547a8)