From 83790071f7fe1492a154a024ac574ca988bfc4b5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 30 May 2026 13:22:18 +0000 Subject: [PATCH] fix: raise ValueError in estimate_effect() when identified estimand is None Previously, calling estimate_effect() with a method whose estimand is None (e.g. 'iv.instrumental_variable' when no instruments are in the graph) would silently return a CausalEstimate with value=None, with only a logger.error message. Callers had no programmatic indication that identification failed. This replaces the silent return with a ValueError that includes a descriptive message explaining which identifier failed and why, matching the contract expected by users (per issue #1551). Closes #1551 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: github-actions[bot] --- dowhy/causal_estimator.py | 7 ++--- .../test_instrumental_variable_estimator.py | 27 +++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/dowhy/causal_estimator.py b/dowhy/causal_estimator.py index 23de0587ac..895a13cd7f 100755 --- a/dowhy/causal_estimator.py +++ b/dowhy/causal_estimator.py @@ -744,9 +744,10 @@ def estimate_effect( ) # Check if estimator's target estimand is identified elif identified_estimand.estimands[identifier_name] is None: - logger.error("No valid identified estimand available.") - return CausalEstimate( - None, None, None, None, None, None, control_value=control_value, treatment_value=treatment_value + raise ValueError( + f"No valid identified estimand for '{identifier_name}'. " + "Ensure that the identification step succeeded for this estimator method " + "(e.g. the graph must contain valid instruments for 'iv.instrumental_variable')." ) if fit_estimator: diff --git a/tests/causal_estimators/test_instrumental_variable_estimator.py b/tests/causal_estimators/test_instrumental_variable_estimator.py index b6705d3ccc..2e9a8df540 100755 --- a/tests/causal_estimators/test_instrumental_variable_estimator.py +++ b/tests/causal_estimators/test_instrumental_variable_estimator.py @@ -3,6 +3,8 @@ import pytest from pytest import mark +import dowhy.datasets +from dowhy import CausalModel from dowhy.causal_estimators.instrumental_variable_estimator import InstrumentalVariableEstimator from .base import SimpleEstimator @@ -78,3 +80,28 @@ def test_average_treatment_effect( cfg["num_instruments"] = 0 with pytest.raises(ValueError): estimator_tester.average_treatment_effect_test(**cfg) + + def test_estimate_effect_raises_when_iv_estimand_is_none(self): + """Regression test for #1551: estimate_effect() must raise ValueError + instead of silently returning CausalEstimate(value=None) when the + identified estimand for 'iv' is None (i.e. no instruments in the graph). + """ + data = dowhy.datasets.linear_dataset( + beta=10, + num_common_causes=2, + num_instruments=0, + num_samples=500, + treatment_is_binary=True, + ) + model = CausalModel( + data=data["df"], + treatment=data["treatment_name"], + outcome=data["outcome_name"], + graph=data["dot_graph"], + ) + identified_estimand = model.identify_effect(proceed_when_unidentifiable=True) + assert identified_estimand.estimands.get("iv") is None, ( + "Precondition: iv estimand must be None when num_instruments=0" + ) + with pytest.raises(ValueError): + model.estimate_effect(identified_estimand, method_name="iv.instrumental_variable")