jd-opensource/joyagent-jdgenie · error · IllegalStateException

Tool execution result is null

Error message

Tool execution result is null

What it means

Thrown by getResultOrThrow when the tool execution nominally succeeded but its stored result object is null. This is a post-condition guard inside a generic DTO accessor: it fires whenever a caller demands the typed result of a ToolResult whose payload was never populated (e.g. a tool completed without producing output), as opposed to the failure branch above which covers non-success status. getResultOrDefault wraps this call and supplies a default in that case, so only callers bypassing the default path hit it.

Solutions

  1. Fix the tool implementation to always set a non-null result on success
  2. Check isSuccess() and result != null before unwrapping
  3. Return a default value via getResultOrDefault semantics

Example fix

// before
T result = toolResult.getResultOrThrow(MyResult.class);
// after
if (toolResult.getResult() == null) {
    return defaultResult;
}
T result = toolResult.getResultOrThrow(MyResult.class);
Defensive patterns

Strategy: validation

Validate before calling

if (toolResult.getResult() == null) { return defaultValue; }

Type guard

boolean hasResult(ToolResult r) { return r != null && r.isSuccess() && r.getResult() != null; }

Try / catch

try {
    T r = toolResult.getResultOrThrow(T.class);
} catch (IllegalStateException e) {
    return defaultValue;
}

Prevention

When it happens

Trigger: Calling getResultOrThrow on a successful ToolResult whose result field was never populated (tool returned nothing, or a code path built ToolResult without setting result).

Common situations: A tool implementation forgot to set the result on success, an async path dropped the payload, or the tool returned void/null for the requested output.

Related errors


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

Appendix: source

Thrown at genie-backend/src/main/java/com/jd/genie/agent/dto/tool/ToolResult.java:158

    }

    /**
     * 检查是否被跳过
     */
    public boolean isSkipped() {
        return status == ExecutionStatus.SKIPPED;
    }

    /**
     * 获取结果或抛出异常
     */
    public <T> T getResultOrThrow(Class<T> resultType) {
        if (!isSuccess()) {
            throw new IllegalStateException("Tool execution failed: " + error);
        }

        if (result == null) {
            throw new IllegalStateException("Tool execution result is null");
        }

        if (!resultType.isInstance(result)) {
            throw new ClassCastException("Result is not of type " + resultType.getName());
        }

        return resultType.cast(result);
    }

    /**
     * 获取结果或返回默认值
     */
    public <T> T getResultOrDefault(Class<T> resultType, T defaultValue) {
        try {
            return getResultOrThrow(resultType);
        } catch (Exception e) {
            return defaultValue;
        }

View on GitHub (pinned to 2417e0b8b6)