Repository navigation
Description
Three formulas return an amount for one household with one tax unit and raise an error once other households or tax units share the simulation.
dc_liheap_paymentraisesParameterNotFoundErrorwhen a simulation holds a DC household that qualifies for LIHEAP and any household outside DC.il_liheap_base_paymentraises the same error when a simulation holds an Illinois household and any household outside Illinois.il_liheapadds it,il_ihwap_categorically_eligibleadds a list that namesil_liheap, andil_ihwap_eligiblereads that result. All three raise too when the Illinois household qualifies for LIHEAP.la_school_readiness_creditraisesValueErrorwhen a simulation holds a Louisiana tax unit, a second tax unit in any state, and more people than tax units. Two Louisiana families trigger it, and so does one Louisiana household of three people in two tax units.la_school_readiness_credit_non_refundableadds it and raises too, andla_school_readiness_credit_refundabledoes when a Louisiana tax unit passes its income test.
For example, for a single adult in DC with no income and $2,000 of heating costs, dc_liheap_payment returns $904 for 2026. Add a single adult in New York to the same simulation, and the same call raises ParameterNotFoundError for gov.states.dc.doee.liheap.payment.electricity.0.
The model still computes household_net_income for a simulation that mixes these households. A caller meets the errors by requesting one of these variables under those conditions: for the three-person Louisiana household, in a test that pairs households from two states, or over a dataset that spans states.
Why they raise
policyengine-core 3.34.2, the version main's uv.lock pins, computes a variable's defined_for mask first. If any member passes, it runs the formula over the whole population and applies the mask to the result afterwards. So every lookup and every product inside a formula has to work for every household and tax unit in the simulation.
dc_liheap_income_levelsetsdefined_for = StateCode.DC, so it returns 0 outside DC.dc_liheap_paymentindexes the electricity and gas matrices with that level, and each matrix holds levels 1 to 10.il_liheap_income_bracketreturns 0 outside Illinois in the same way.il_liheap_base_paymentindexes four matrices with it, and each matrix holds brackets 1 to 4.il_liheapadds the base payment, and the IHWAP categorical eligibility list namesil_liheap.la_school_readiness_creditmultiplies the tax unit's child care credits by each person's rate. The first array has one value per tax unit and the second has one per person. NumPy broadcasts them only when the simulation holds one tax unit, or one person in every tax unit.
What the code should do
Each formula should return the same amount for each household whatever other households or tax units share the simulation. vt_renter_credit does this for its county tables: before the lookup, it gives every household outside Vermont a county the tables hold.
Reproduction
This script runs each variable for one household and then for the same household beside a single adult in New York, at commit 3f6e604:
from policyengine_us import Simulation
YEAR = 2026
GROUPS = ["households", "tax_units", "spm_units", "families"]
def simulate(*households):
situation = {"people": {}, "marital_units": {}, **{group: {} for group in GROUPS}}
for i, (state, people, tax_unit_inputs) in enumerate(households):
members = [f"person_{i}_{j}" for j in range(len(people))]
for name, person in zip(members, people):
situation["people"][name] = {k: {YEAR: v} for k, v in person.items()}
situation["marital_units"][f"marital_unit_{name}"] = {"members": [name]}
for group in GROUPS:
situation[group][f"{group}_{i}"] = {"members": members}
situation["households"][f"households_{i}"]["state_code"] = {YEAR: state}
for k, v in tax_unit_inputs.items():
situation["tax_units"][f"tax_units_{i}"][k] = {YEAR: v}
return Simulation(situation=situation)
adult = {"age": 40, "heating_expense_person": 2_000}
parent, child = {"age": 30}, {"age": 3, "la_quality_rating_of_child_care_facility": 5}
dc, il, ny = [(state, [adult], {}) for state in ("DC", "IL", "NY")]
la = ("LA", [parent, child], {"la_refundable_cdcc": 50})
for variable, home in [
("dc_liheap_payment", dc),
("il_liheap_base_payment", il),
("il_liheap", il),
("il_ihwap_eligible", il),
("la_school_readiness_credit", la),
]:
print(variable, "alone:", simulate(home).calculate(variable, YEAR))
try:
both = simulate(home, ny).calculate(variable, YEAR)
print(variable, "with a New York household:", both)
except Exception as error:
print(variable, "with a New York household:", type(error).__name__, error)It prints:
dc_liheap_payment alone: [904.]
dc_liheap_payment with a New York household: ParameterNotFoundError The parameter 'gov.states.dc.doee.liheap.payment.electricity.0' was not found in the 2026-01-01 tax and benefit system.
il_liheap_base_payment alone: [910.]
il_liheap_base_payment with a New York household: ParameterNotFoundError The parameter 'gov.states.il.dceo.liheap.payment.matrix.all_electric.0' was not found in the 2026-01-01 tax and benefit system.
il_liheap alone: [910.]
il_liheap with a New York household: ParameterNotFoundError The parameter 'gov.states.il.dceo.liheap.payment.matrix.all_electric.0' was not found in the 2026-01-01 tax and benefit system.
il_ihwap_eligible alone: [ True]
il_ihwap_eligible with a New York household: ParameterNotFoundError The parameter 'gov.states.il.dceo.liheap.payment.matrix.all_electric.0' was not found in the 2026-01-01 tax and benefit system.
la_school_readiness_credit alone: [100.]
la_school_readiness_credit with a New York household: ValueError operands could not be broadcast together with shapes (2,) (3,)
We ran it with policyengine-core 3.33.2, which orders the mask and the formula the same way as 3.34.2.
In further runs, dc_liheap_payment returns [904. 904.] for two DC households that both qualify and [0. 0.] for a DC household over the income limit beside the New York one. la_school_readiness_credit raises the same ValueError for a Louisiana family beside a single Louisiana adult, in a second household or in a second tax unit of the family's household. It returns [0. 0.] for two single Louisiana adults. For an Illinois household over the income limit beside the New York one, il_liheap_base_payment still raises, while il_liheap returns [0. 0.].
Fix
For DC and Illinois, clip the income level to the matrix's rows before the lookup (1 to 10 in DC, 1 to 4 in Illinois), as nv_liheap does for its size key. policyengine-core still zeroes the out-of-state rows through defined_for. For Louisiana, multiply by tax_unit.project(child_care_credit), which gives each person their own tax unit's credit. With those three changes applied as a reform, one simulation of DC, Illinois, New York and Louisiana households runs, and every household keeps the amount it gets alone.
Related
- Fix WA property tax exemption crash for households outside Washington #10113 fixes the same lookup error in
wa_pte_tierandwa_pte_income_eligible, which still raise at this commit for a Washington household beside a Missouri one. - Guard county-keyed lookups in VT renter credit, MN CCAP, WI Shares and MD CCS #10116 guards county-keyed lookups in the Vermont renter credit, Minnesota CCAP, Wisconsin Shares and Maryland CCS. Count property tax and rent refunds paid outside the income tax in household and SPM benefits #10725 already brought the Vermont guard to main.
- Add a national LIHEAP total, an Illinois regular heating payment and LIHEAP cooling registry notes #10730 adds a national
liheaptotal that sumsdc_liheap_paymentand, throughil_liheap_regular_heating,il_liheap_base_payment. That total would raise for a population that holds a qualifying DC or Illinois household and a household in another state. - Nebraska's school readiness credit raises an error for an eligible child care worker who lives with a child or an adult without a level, where Nebraska bases the credit on the worker's own level #10785 reports an error with the same
defined_forcause in Nebraska's school readiness credit. - Adjust the Louisiana school readiness tax credit to match model standards #4503 notes that the net income tree leaves out the Louisiana school readiness credit.
Activity