Summary
The request models bound line quantities with qty: int = Field(gt=0) but set no upper bound (src/quartermaster/api/schemas.py:17 for OrderLineInput, :110 for ReceiptLineInput). The backing columns are Integer (32-bit) in src/quartermaster/adapters/postgres/tables.py (ordered_qty:97, expected_qty:131, qty_on_hand:74, etc.), and the domain types (OrderLine, ReceiptLine, StockLevel) also impose no upper bound.
A request with qty > 2_147_483_647 passes validation and the domain layer, then fails at INSERT with a numeric-out-of-range error from the driver. That error is not mapped in src/quartermaster/api/errors.py:34-45, so it falls through to the catch-all (_internal_error_handler) and the client receives 500 internal_error for a value it supplied.
Impact
A foreseeable, client-controlled input produces a 500 instead of a 422. Affects create_order, create_receipt, and receive.
Suggested fix
Add an upper bound on the request models, e.g. Field(gt=0, le=2_147_483_647) (or a single domain-defined maximum), so oversized quantities are rejected as 422 at the boundary. Consider mirroring the bound in the domain constructors so the in-memory types and the DB columns agree.
Test gap
No test posts a quantity above the column limit; tests/unit/test_api_schemas.py only covers qty = 0.
Summary
The request models bound line quantities with
qty: int = Field(gt=0)but set no upper bound (src/quartermaster/api/schemas.py:17forOrderLineInput,:110forReceiptLineInput). The backing columns areInteger(32-bit) insrc/quartermaster/adapters/postgres/tables.py(ordered_qty:97,expected_qty:131,qty_on_hand:74, etc.), and the domain types (OrderLine,ReceiptLine,StockLevel) also impose no upper bound.A request with
qty > 2_147_483_647passes validation and the domain layer, then fails atINSERTwith a numeric-out-of-range error from the driver. That error is not mapped insrc/quartermaster/api/errors.py:34-45, so it falls through to the catch-all (_internal_error_handler) and the client receives500 internal_errorfor a value it supplied.Impact
A foreseeable, client-controlled input produces a
500instead of a422. Affectscreate_order,create_receipt, andreceive.Suggested fix
Add an upper bound on the request models, e.g.
Field(gt=0, le=2_147_483_647)(or a single domain-defined maximum), so oversized quantities are rejected as422at the boundary. Consider mirroring the bound in the domain constructors so the in-memory types and the DB columns agree.Test gap
No test posts a quantity above the column limit;
tests/unit/test_api_schemas.pyonly coversqty = 0.