Batu Lab NotesPractical developer guides

Attach a stable error code to a validation error

By Batu · English technical notes

Attach a stable code attribute to a validation exception, then let consumers branch on that code rather than on prose. Here, a blank identifier raises ValidationError with code == 'blank_id', while a negative count raises one with code == 'negative_count'. The message remains useful for a human, but changing its wording does not change the programmatic contract.

The validator owns classification of invalid inputs. It checks the identifier first, then the count, and raises the same exception type with a distinct stable code for each rule. The caller catches that narrow domain exception and appends error.code. This makes the output deterministic and avoids fragile conditions such as if 'blank' in str(error), which can break after localization, punctuation edits, or improved wording.

An error code should be documented as part of the API: choose names that describe the rule, keep them stable, and add new codes rather than silently repurposing an existing one. This minimal class does not provide localization, field paths, HTTP status mapping, or a formal enum. Those may be useful in a larger boundary, but they are separate design choices. The fixture demonstrates only blank and negative inputs; its assertions establish that these two inputs yield their planned codes independently of the attached messages.

This example uses no newer API; it runs on supported Python 3 versions.

AI assistance disclosure: this article was drafted with AI assistance and the synthetic example is intended to be run locally.

Source: Python’s errors and exceptions tutorial covers user-defined exceptions and exception handling.

class ValidationError(Exception):
    def __init__(self, code, message):
        self.code = code
        super().__init__(message)


def validate(identifier, count):
    if not identifier:
        raise ValidationError("blank_id", "identifier must not be blank")
    if count < 0:
        raise ValidationError("negative_count", "count must not be negative")
    return {"id": identifier, "count": count}


codes = []
for identifier, count in [("", 1), ("item-7", -1)]:
    try:
        validate(identifier, count)
    except ValidationError as error:
        codes.append(error.code)

assert codes == ["blank_id", "negative_count"]
print(codes)
['blank_id', 'negative_count']