# How Hypster Ensures Type Safety and Validates Hyper-Parameters

> Hypster ensures type safety with layered validation checking function signatures parameter types and detecting unknown duplicates for robust parameter validation.

- Repository: [Gilad Rubin/hypster](https://github.com/gilad-rubin/hypster)
- Tags: deep-dive
- Published: 2026-03-02

---

**Hypster enforces type safety through a layered validation system that checks function signatures, validates parameter types via specialized validator classes, and detects unknown or duplicate parameters during configuration execution.**

Hypster is a Python library for managing hyper-parameter configurations developed by gilad-rubin. The library implements rigorous type safety and validation mechanisms to prevent runtime errors caused by invalid parameter types, out-of-bounds values, or misconfigured options. According to the source code in `gilad-rubin/hypster`, this validation occurs across multiple layers from initial function inspection through final parameter binding.

## Function Signature Validation

Before executing any configuration logic, Hypster validates that user-defined configuration functions adhere to a strict contract. In [`src/hypster/utils.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/utils.py), the `validate_config_func_signature` function inspects the callable and asserts that its first argument is named **hp** and is annotated with the `HP` type.

If the signature is malformed—such as missing the `hp` parameter or lacking the correct type annotation—the system raises a clear `ValueError` immediately. This check occurs at lines 85-115 in [`utils.py`](https://github.com/gilad-rubin/hypster/blob/main/utils.py), ensuring that all downstream validation operates on correctly structured configuration functions.

## Validator Classes for Type Safety

Concrete validation logic resides in [`src/hypster/hp_calls.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/hp_calls.py). Specialized validator classes enforce type constraints for each parameter category, with every validator implementing `validate_value` and optionally `validate_bounds`.

**IntValidator** ensures supplied values are integers or safely convertible from floats, raising `HPCallError` on type mismatches. When `strict=True`, it rejects implicit float-to-int conversions that would lose precision, as implemented at lines 58-60, while general validation spans lines 56-70.

**FloatValidator** guarantees float types or converts from integers when strict mode is disabled (lines 75-85). **TextValidator**, **BoolValidator**, **SelectValidator**, and **MultiValidator** perform analogous checks for strings, booleans, enumerated choices, and list-valued parameters at lines 91-127.

## Centralized Validation in the HP Class

All public HP methods—including `_int`, `_float`, `_text`, `_bool`, `select`, and `multi_select`—delegate to private helper methods in [`src/hypster/hp.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/hp.py). These helpers orchestrate the validation sequence:

- `_validate_name_not_called` ensures parameter names are unique and not reused within the same configuration
- `_handle_single_value` and `_handle_multi_value` fetch user-provided values or defaults, then invoke the appropriate validator's `validate_value` method
- When bounds (`min` / `max`) are declared, the helper calls `validator.validate_bounds` to enforce numeric limits, as seen at lines 48-50 in [`hp.py`](https://github.com/gilad-rubin/hypster/blob/main/hp.py)

This centralized approach guarantees consistent error messages and validation behavior across all parameter types.

## Strict Mode for Numeric Precision

For numeric parameters, Hypster provides a `strict` flag that controls type coercion behavior. When `strict=True`, validators reject implicit conversions entirely. For example, `IntValidator` will raise an error if passed `32.5` even if it could theoretically be truncated, preventing silent precision loss. This mode is particularly critical for scientific computing configurations where exact integer semantics are required.

## Unknown and Duplicate Parameter Detection

After user functions execute, Hypster performs a final validation pass to catch misspelled or unreachable parameters. The `HP` class tracks every called parameter in `self.called_params`. In [`src/hypster/core.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/core.py), the `_handle_unknown_parameters` function (lines 73-106) compares supplied values against the set of actually called parameters, emitting warnings or errors for keys that were never accessed during configuration execution.

This layer prevents silent failures caused by typos in parameter names or attempting to set values for parameters that have been removed from the configuration.

## Practical Implementation Examples

The following examples demonstrate Hypster's validation layers in action:

```python
from hypster import instantiate, HP

# Typed parameters with bounds and strict mode

def cfg(hp: HP):
    # int – strict=False allows safe conversion from float

    batch = hp.int(32, name="batch", min=1, max=512, strict=False)
    # float – strict=True rejects int values

    lr = hp.float(0.01, name="lr", min=0.0, max=1.0, strict=True)
    # bool and text parameters

    use_gpu = hp.bool(True, name="use_gpu")
    model_name = hp.text("resnet", name="model")
    return {"batch": batch, "lr": lr, "gpu": use_gpu, "model": model_name}

# Valid instantiation

config = instantiate(cfg, values={"batch": 64, "lr": 0.001})
print(config)   # {'batch': 64, 'lr': 0.001, 'gpu': True, 'model': 'resnet'}

```

Validation failures raise descriptive errors:

```python

# Bounds violation

try:
    instantiate(cfg, values={"batch": 0})   # below minimum

except ValueError as e:
    print(e)   # Parameter 'batch': value 0 is below minimum bound 1

# Strict mode rejection

try:
    instantiate(cfg, values={"batch": 32.5})   # float precision loss

except ValueError as e:
    print(e)   # Parameter 'batch': float 32.5 would lose precision ...

```

Enumerated parameters enforce option constraints:

```python
def cfg_select(hp: HP):
    optimizer = hp.select(["sgd", "adam"], name="optimizer", options_only=True)
    return optimizer

# Unknown option detection

try:
    instantiate(cfg_select, values={"optimizer": "rmsprop"})
except ValueError as e:
    print(e)   # 'rmsprop' not in allowed options. Available: ['sgd', 'adam']

```

Type safety propagates through nested configurations:

```python
def child(hp: HP):
    hidden = hp.int(128, name="hidden", min=1)
    return hidden

def parent(hp: HP):
    hp.nest(child, name="encoder")
    return "done"

# Nested parameter validation

print(instantiate(parent, values={"encoder.hidden": 256}))

```

## Summary

- **Signature validation** in [`utils.py`](https://github.com/gilad-rubin/hypster/blob/main/utils.py) ensures configuration functions accept an `hp: HP` parameter before execution begins.
- **Specialized validators** in [`hp_calls.py`](https://github.com/gilad-rubin/hypster/blob/main/hp_calls.py) enforce type constraints for integers, floats, booleans, text, and selections, with optional strict mode for numeric precision.
- **Central handling** in [`hp.py`](https://github.com/gilad-rubin/hypster/blob/main/hp.py) coordinates name uniqueness checks, value validation, and bounds enforcement through `_handle_single_value` and related helpers.
- **Strict mode** prevents implicit type conversions that could silently alter numeric values in scientific computations.
- **Unknown parameter detection** in [`core.py`](https://github.com/gilad-rubin/hypster/blob/main/core.py) compares supplied values against actually called parameters to catch typos and obsolete configuration keys.

## Frequently Asked Questions

### What happens if I pass a float to an int parameter in Hypster?

The behavior depends on the `strict` flag. When `strict=False` (default), `IntValidator` accepts floats that represent whole numbers (e.g., `32.0`) but rejects values like `32.5` that would lose precision. When `strict=True`, the validator rejects any float input, requiring explicit integer types. In all cases, invalid conversions raise `HPCallError` with descriptive messages indicating the parameter name and problematic value.

### How does Hypster detect unknown or misspelled parameters?

Hypster tracks every parameter accessed during configuration execution in `self.called_params`. After the configuration function completes, `core._handle_unknown_parameters` (lines 73-106) compares the keys in the user-supplied values dictionary against this set of called parameters. If a supplied key was never accessed—indicating a typo or obsolete parameter—the system emits a warning or error, preventing silent configuration failures.

### What is the purpose of strict mode in Hypster validators?

Strict mode controls type coercion behavior for numeric parameters. When enabled via `strict=True` in methods like `hp.int()` or `hp.float()`, validators reject implicit conversions between integers and floats. This prevents subtle bugs in machine learning pipelines where `1.0` (float) might behave differently from `1` (int) in downstream libraries, or where precision loss from float-to-int conversion could alter experimental results.

### How does Hypster validate configuration function signatures?

Before executing a configuration, `utils.validate_config_func_signature` inspects the callable to verify its first argument is named `hp` and carries the `HP` type annotation. This check occurs at lines 85-115 in [`src/hypster/utils.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/utils.py). If the signature is incorrect—such as missing the parameter or having the wrong type hint—Hypster raises a `ValueError` immediately, ensuring that all configuration functions follow the expected interface contract.