validate_metadata leaks decimal.InvalidOperation on bad fiat_amount #38

Open
opened 2026-06-06 21:35:33 +00:00 by padreug · 0 comments
Owner

What

core.validation.validate_metadata() is meant to wrap parse failures of fiat_amount into a ValidationError, but the except clause doesn't catch the actual exception raised by Decimal(). The raw decimal.InvalidOperation propagates out, breaking the contract.

Reproduce

from libra.core.validation import validate_metadata
validate_metadata({"fiat_amount": "not-a-number", "fiat_currency": "EUR"})

Raises decimal.InvalidOperation: [<class 'decimal.ConversionSyntax'>] instead of ValidationError("Invalid fiat_amount: not-a-number").

Where

core/validation.py:282-289:

if has_fiat_amount:
    try:
        Decimal(str(metadata["fiat_amount"]))
    except (ValueError, TypeError) as e:
        raise ValidationError(
            f"Invalid fiat_amount: {metadata['fiat_amount']}",
            {"error": str(e)}
        )

decimal.InvalidOperation inherits from ArithmeticError, not ValueError or TypeError, so the catch silently fails.

Fix

Add decimal.InvalidOperation to the catch tuple:

from decimal import Decimal, InvalidOperation
...
except (ValueError, TypeError, InvalidOperation) as e:
    raise ValidationError(...)

Surfaced from

The pure-function unit tests in tests/test_unit.py::test_validate_metadata_fiat_amount_invalid_decimal_raises — the test was asserting the documented behaviour (ValidationError for bad input), and that's what surfaced the gap.

Scope

One-line fix in core/validation.py. Worth grepping the rest of validation.py and crud.py for similar try: Decimal(...) except ValueError patterns that have the same hole.

## What `core.validation.validate_metadata()` is meant to wrap parse failures of `fiat_amount` into a `ValidationError`, but the `except` clause doesn't catch the actual exception raised by `Decimal()`. The raw `decimal.InvalidOperation` propagates out, breaking the contract. ## Reproduce ```python from libra.core.validation import validate_metadata validate_metadata({"fiat_amount": "not-a-number", "fiat_currency": "EUR"}) ``` Raises `decimal.InvalidOperation: [<class 'decimal.ConversionSyntax'>]` instead of `ValidationError("Invalid fiat_amount: not-a-number")`. ## Where `core/validation.py:282-289`: ```python if has_fiat_amount: try: Decimal(str(metadata["fiat_amount"])) except (ValueError, TypeError) as e: raise ValidationError( f"Invalid fiat_amount: {metadata['fiat_amount']}", {"error": str(e)} ) ``` `decimal.InvalidOperation` inherits from `ArithmeticError`, not `ValueError` or `TypeError`, so the catch silently fails. ## Fix Add `decimal.InvalidOperation` to the catch tuple: ```python from decimal import Decimal, InvalidOperation ... except (ValueError, TypeError, InvalidOperation) as e: raise ValidationError(...) ``` ## Surfaced from The pure-function unit tests in `tests/test_unit.py::test_validate_metadata_fiat_amount_invalid_decimal_raises` — the test was asserting the documented behaviour (`ValidationError` for bad input), and that's what surfaced the gap. ## Scope One-line fix in `core/validation.py`. Worth grepping the rest of `validation.py` and `crud.py` for similar `try: Decimal(...) except ValueError` patterns that have the same hole.
padreug referenced this issue from a commit 2026-06-07 13:39:52 +00:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
aiolabs/libra#38
No description provided.