Summary
While investigating PolicyEngine/policyengine.py#344, we found that a married-couple-with-children household can assign negative Marriage Allowance to child records, which then creates taxable earned income and income tax for children with no income.
@vahid-ahmadi could you please confirm whether this is in fact an issue, rather than intentional behavior or a misunderstanding of UK tax law?
Observed behavior
For a household with two adults and two children:
from policyengine_uk import Simulation
situation = {
"people": {
"person_0": {"age": {"2026": 42}, "employment_income": {"2026": 55000}},
"person_1": {"age": {"2026": 40}, "employment_income": {"2026": 35000}},
"person_2": {"age": {"2026": 8}},
"person_3": {"age": {"2026": 3}},
},
"benunits": {
"benunit_0": {
"members": ["person_0", "person_1", "person_2", "person_3"]
}
},
"households": {
"household_0": {
"members": ["person_0", "person_1", "person_2", "person_3"]
}
},
}
sim = Simulation(situation=situation)
for variable in [
"marital_status",
"tax_band",
"meets_marriage_allowance_income_conditions",
"unused_personal_allowance",
"partners_unused_personal_allowance",
"marriage_allowance",
"earned_taxable_income",
"income_tax",
]:
values = sim.calculate(variable, 2026)
if hasattr(values, "decode_to_str"):
values = values.decode_to_str()
print(variable, list(values))
Current output on main / 2.88.13:
marital_status [MARRIED, MARRIED, MARRIED, MARRIED]
tax_band [HIGHER, BASIC, NONE, NONE]
meets_marriage_allowance_income_conditions [False, True, True, True]
unused_personal_allowance [0.0, 0.0, 12570.0, 12570.0]
partners_unused_personal_allowance [0.0, 0.0, -12570.0, -12570.0]
marriage_allowance [0.0, 0.0, -12570.0, -12570.0]
earned_taxable_income [42430.0, 22430.0, 12570.0, 12570.0]
income_tax [9432.0, 4486.0, 2514.0, 2514.0]
This causes each child to receive income_tax == 2514.0, which is exactly 20% of the personal allowance.
Why this appears to happen
The relevant path appears to be:
marital_status maps every person in a married benefit unit to MARRIED, including children.
gov.hmrc.income_tax.allowances.marriage_allowance.eligible_bands includes NONE after the Marriage Allowance eligibility change.
- Children have tax band
NONE, so meets_marriage_allowance_income_conditions is true for them.
partners_unused_personal_allowance returns benunit.sum(is_adult * unused_personal_allowance) - pa; for children this becomes 0 - 12570 == -12570.
marriage_allowance allows that negative amount through.
earned_taxable_income subtracts marriage_allowance, so subtracting -12570 creates 12570 taxable earned income.
income_tax then taxes that at the basic rate, producing 2514.
Context
This surfaced because PolicyEngine/policyengine.py#344 updates the UK package from policyengine-uk==2.88.0 to 2.88.6, and the UK household snapshot test for a married couple with two children began failing:
person[2].income_tax: expected 0.0, got 2514.0
person[3].income_tax: expected 0.0, got 2514.0
household.household_tax: expected 18982.05, got 24010.05
The same behavior is still live on current policyengine-uk main / 2.88.13. No relevant changes appear between 2.88.6 and HEAD in the Marriage Allowance/marital-status path.
Question
Should children in a married benefit unit ever be considered MARRIED for Marriage Allowance purposes, or eligible transferors under the NONE tax-band rule? If not, the likely fix is to guard Marriage Allowance eligibility and/or marital status so the transferor logic applies only to adults/spouses, and to prevent negative marriage_allowance values from flowing into taxable income.
Summary
While investigating PolicyEngine/policyengine.py#344, we found that a married-couple-with-children household can assign negative Marriage Allowance to child records, which then creates taxable earned income and income tax for children with no income.
@vahid-ahmadi could you please confirm whether this is in fact an issue, rather than intentional behavior or a misunderstanding of UK tax law?
Observed behavior
For a household with two adults and two children:
Current output on
main/2.88.13:This causes each child to receive
income_tax == 2514.0, which is exactly 20% of the personal allowance.Why this appears to happen
The relevant path appears to be:
marital_statusmaps every person in a married benefit unit toMARRIED, including children.gov.hmrc.income_tax.allowances.marriage_allowance.eligible_bandsincludesNONEafter the Marriage Allowance eligibility change.NONE, someets_marriage_allowance_income_conditionsis true for them.partners_unused_personal_allowancereturnsbenunit.sum(is_adult * unused_personal_allowance) - pa; for children this becomes0 - 12570 == -12570.marriage_allowanceallows that negative amount through.earned_taxable_incomesubtractsmarriage_allowance, so subtracting-12570creates12570taxable earned income.income_taxthen taxes that at the basic rate, producing2514.Context
This surfaced because PolicyEngine/policyengine.py#344 updates the UK package from
policyengine-uk==2.88.0to2.88.6, and the UK household snapshot test for a married couple with two children began failing:The same behavior is still live on current
policyengine-ukmain/2.88.13. No relevant changes appear between2.88.6andHEADin the Marriage Allowance/marital-status path.Question
Should children in a married benefit unit ever be considered
MARRIEDfor Marriage Allowance purposes, or eligible transferors under theNONEtax-band rule? If not, the likely fix is to guard Marriage Allowance eligibility and/or marital status so the transferor logic applies only to adults/spouses, and to prevent negativemarriage_allowancevalues from flowing into taxable income.