jd-opensource/joyagent-jdgenie · error · RuntimeException

tableRag result is null

Error message

tableRag result is null

What it means

TableRagService.tableRag throws this when the HTTP response from the data-agent TABLE_RAG_URL endpoint cannot be parsed into a TableRagResult or parses to an object with a null code. It indicates the remote table-RAG service returned an empty, malformed, or non-standard body, so no valid response envelope exists.

Solutions

  1. Verify dataAgentConfig.getAgentUrl() + TABLE_RAG_URL is reachable (curl the endpoint with an equivalent payload).
  2. Log the raw response string res before parsing to see what the remote service actually returned.
  3. Check data-agent service health/logs for the corresponding traceId/requestId.
  4. Wrap the POST with retry/timeout handling so transient network failures surface as a clear upstream error instead of a null parse.

Example fix

// before
TableRagResult tableRagResult = JSONObject.parseObject(res, TableRagResult.class);
if (tableRagResult == null || tableRagResult.getCode() == null) {
    throw new RuntimeException("tableRag result is null");
}
// after
if (StringUtils.isBlank(res)) {
    throw new RuntimeException("tableRag returned empty body, url=" + dataAgentConfig.getAgentUrl() + TABLE_RAG_URL);
}
TableRagResult tableRagResult = JSONObject.parseObject(res, TableRagResult.class);
if (tableRagResult == null || tableRagResult.getCode() == null) {
    throw new RuntimeException("tableRag result unparseable, body=" + res);
}
Defensive patterns

Strategy: validation

Validate before calling

// java
if (StringUtils.isBlank(res)) {
    throw new IllegalStateException("tableRag upstream returned empty body");
}

Type guard

TableRagResult safeParse(String res) {
    if (StringUtils.isBlank(res)) return null;
    try {
        return JSONObject.parseObject(res, TableRagResult.class);
    } catch (Exception e) {
        return null;
    }
}

Try / catch

try {
    TableRagResult r = tableRagService.tableRag(req);
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().contains("tableRag result is null")) {
        log.error("tableRag upstream unavailable, check dataAgent url/health");
    }
    throw e;
}

Prevention

When it happens

Trigger: OkHttpUtil.postJsonBody returns null or an empty/garbage string (network failure path, agent URL wrong, gateway returning HTML/empty body), making JSONObject.parseObject(res, TableRagResult.class) yield null or an object without code.

Common situations: Data-agent service down or returning 5xx with empty body; dataAgentConfig.getAgentUrl() misconfigured or pointing to a wrong port; proxy/gateway intercepting the request and returning an error page; serialization/deserialization mismatch after TableRagResult model changes.

Related errors


AI-assisted analysis of jd-opensource/joyagent-jdgenie@2417e0b8b6 (2026-09-08). Data as JSON: /api/errors/f37389f71573d596. Report an issue: GitHub.

Appendix: source

Thrown at genie-backend/src/main/java/com/jd/genie/service/TableRagService.java:45

    @Autowired
    DataAgentConfig dataAgentConfig;

    public List<ChatSchemaDto> tableRag(NL2SQLReq req) throws IOException {
        if (!dataAgentConfig.getEsConfig().getEnable() && !dataAgentConfig.getQdrantConfig().getEnable()) {
            log.info("{},{} 未开启向量和es,不进行tableRag",req.getTraceId(),req.getRequestId());
            return new ArrayList<>();
        }
        String res;
        try {
            res = OkHttpUtil.postJsonBody(dataAgentConfig.getAgentUrl() + TABLE_RAG_URL, null, JSONObject.toJSONString(req));
        } catch (Exception e) {
            log.warn("{},{} tableRag server error,retry:{}",req.getTraceId(),req.getRequestId(), e.getMessage());
            res = OkHttpUtil.postJsonBody(dataAgentConfig.getAgentUrl() + TABLE_RAG_URL, null, JSONObject.toJSONString(req));
        }
        log.info("{},{} tableRag result:{}", req.getTraceId(),req.getRequestId(),res);
        TableRagResult tableRagResult = JSONObject.parseObject(res, TableRagResult.class);
        if (tableRagResult == null || tableRagResult.getCode() == null) {
            throw new RuntimeException("tableRag result is null");
        }
        if (tableRagResult.getCode() != 200) {
            throw new RuntimeException("tableRag server return error");
        }
        List<TableRagResult.TableRagData> data = tableRagResult.getData();
        if (CollectionUtils.isEmpty(data)) {
            throw new RuntimeException("tableRag result data is empty");
        }
        return data.stream()
                .filter(Objects::nonNull)
                .map(TableRagResult.TableRagData::getSchemaList)
                .filter(CollectionUtils::isNotEmpty)
                .flatMap(Collection::stream)
                .collect(Collectors.toList());
    }
}

View on GitHub (pinned to 2417e0b8b6)