diff --git a/dowhy/causal_estimator.py b/dowhy/causal_estimator.py index 23de0587a..895a13cd7 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 b6705d3cc..2e9a8df54 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")