{"record":{"id":"ba154595d117d7cb","repo":"jd-opensource/joyagent-jdgenie","slug":"tool-execution-result-is-null","errorCode":null,"errorMessage":"Tool execution result is null","messagePattern":"Tool execution result is null","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"genie-backend/src/main/java/com/jd/genie/agent/dto/tool/ToolResult.java","lineNumber":158,"sourceCode":"    }\n\n    /**\n     * 检查是否被跳过\n     */\n    public boolean isSkipped() {\n        return status == ExecutionStatus.SKIPPED;\n    }\n\n    /**\n     * 获取结果或抛出异常\n     */\n    public <T> T getResultOrThrow(Class<T> resultType) {\n        if (!isSuccess()) {\n            throw new IllegalStateException(\"Tool execution failed: \" + error);\n        }\n\n        if (result == null) {\n            throw new IllegalStateException(\"Tool execution result is null\");\n        }\n\n        if (!resultType.isInstance(result)) {\n            throw new ClassCastException(\"Result is not of type \" + resultType.getName());\n        }\n\n        return resultType.cast(result);\n    }\n\n    /**\n     * 获取结果或返回默认值\n     */\n    public <T> T getResultOrDefault(Class<T> resultType, T defaultValue) {\n        try {\n            return getResultOrThrow(resultType);\n        } catch (Exception e) {\n            return defaultValue;\n        }","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/jd-opensource/joyagent-jdgenie/blob/2417e0b8b636d941ad5fb14c59b20dddfef5375d/genie-backend/src/main/java/com/jd/genie/agent/dto/tool/ToolResult.java#L140-L176","documentation":"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.","triggerScenarios":"Calling getResultOrThrow on a successful ToolResult whose result field was never populated (tool returned nothing, or a code path built ToolResult without setting result).","commonSituations":"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.","solutions":["Fix the tool implementation to always set a non-null result on success","Check isSuccess() and result != null before unwrapping","Return a default value via getResultOrDefault semantics"],"exampleFix":"// before\nT result = toolResult.getResultOrThrow(MyResult.class);\n// after\nif (toolResult.getResult() == null) {\n    return defaultResult;\n}\nT result = toolResult.getResultOrThrow(MyResult.class);","handlingStrategy":"validation","validationCode":"if (toolResult.getResult() == null) { return defaultValue; }","typeGuard":"boolean hasResult(ToolResult r) { return r != null && r.isSuccess() && r.getResult() != null; }","tryCatchPattern":"try {\n    T r = toolResult.getResultOrThrow(T.class);\n} catch (IllegalStateException e) {\n    return defaultValue;\n}","preventionTips":["Ensure tool implementations always set a non-null result on success","Check getResult() before getResultOrThrow","Prefer getResultOrDefault for optional results"],"tags":["java","agent","null-result"],"backgroundTag":"null-argument","analyzedSha":"2417e0b8b636d941ad5fb14c59b20dddfef5375d","analyzedAt":"2026-09-08T11:28:19.414Z","contentChangedAt":"2026-09-08T11:28:19.414Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}