PolicyEngine / PolicyEngine/policyengine-household-api

Malformed policy period keys should return 400 Bad Request, not 500, and be documented

Open
#1,628 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
1
Forks
3
Avg merge
6h 34m
Merged PRs (30d)
8

Description

Current behavior

POST /<country_id>/calculate validates the policy dict's period keys up front: every key must be two dot-separated instants ("2026-01-01.2026-12-31"). A malformed key — a bare instant ("2026-01-01"), a bare year ("2026"), extra segments ("a.b.c"), or garbage — is rejected with HTTP 500.

The 500 status is deliberate for now: it matches the endpoint's long-standing behavior, where malformed period keys reached the core engine's time_period.split(".") and blew up mid-calculation as a 500. Keeping the status while adding the up-front check meant existing client behavior didn't change in the same release that introduced the validation layer.

Why this matters

Before the validation layer existed, the two country paths had silently diverged: the core simulation path (US/CA/NG/IL) crashed with a 500 on malformed keys, while the UK wrapper path (policyengine-uk ≥ 2.43, via Scenario.from_reform) accepted bare instants and applied the parameter change to a single day — returning near-baseline numbers with a 200 and no warning. The validation layer closes that hole uniformly.

Proposed change

  1. A malformed policy object is a client error, not a server error: return 400 Bad Request with the same descriptive message (Invalid policy period key ... Expected two dot-separated instants, e.g. "2026-01-01.2026-12-31".).
  2. Document the policy period-key grammar in the public API docs (docs app), alongside the household period-key conventions that are already documented.
  3. Decide whether bare year keys ({"2026": value} meaning the whole year) should be deliberately supported on both paths as a convenience — they have unambiguous semantics, unlike bare date keys. If so, that's an additive grammar change to make everywhere at once, not a country-specific accident.

Where the code lives

_validate_policy_periods in libs/household-api/policyengine_household_api/endpoints/household.py, called from get_calculate with an explicit 500 and a comment pointing at this issue.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in libs/household-api/policyengine_household_api/endpoints/household.py at _validate_policy_periods and its call from get_calculate, including the existing 500 comment. Confirm the malformed policy response becomes 400 with the stated message, document the period-key grammar in the docs app, and resolve whether bare year keys are supported consistently.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
api, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.