# How to Debug Configuration Issues and Parameter Resolution Problems in Hypster

> Debug Hypster configuration issues and parameter resolution problems. Learn how Hypster detects unknown or unreachable parameters and resolves config values with its two stage pipeline.

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

---

**Hypster resolves configuration values through a two-stage pipeline where `instantiate` creates an `HP` instance and executes your config function, comparing user-supplied keys against `called_params` to detect unknown or unreachable parameters with typo suggestions.**

Hypster is a Python library for managing complex configuration objects through code-first configuration functions. When parameter resolution fails or unexpected keys appear, understanding the internal instantiation pipeline—from signature validation in [`src/hypster/utils.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/utils.py) to parameter tracking in [`src/hypster/hp.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/hp.py)—is essential for effective debugging.

## Understanding Hypster's Two-Stage Configuration Pipeline

Hypster builds configuration objects through a strict two-stage process implemented in [`src/hypster/core.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/core.py). First, the `instantiate` function (lines 17-66) creates an `HP` instance from your values mapping and executes your configuration function. Second, calls to `hp.int()`, `hp.select()`, or `hp.nest()` inside that function retrieve, validate, and record parameter values in the `called_params` set.

The library maintains a shared registry of accessed parameters across nested configuration blocks. When execution completes, `_handle_unknown_parameters` (lines 73-106 in [`src/hypster/core.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/core.py)) compares the keys you supplied against the `called_params` set populated during execution. Mismatches trigger warnings or errors depending on your `on_unknown` setting, with suggestions generated by `suggest_similar_names` in [`src/hypster/utils.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/utils.py) using `difflib.SequenceMatcher`.

## Common Configuration Errors and Their Root Causes

Configuration failures typically originate from three layers: signature validation, parameter name collisions, or value validation.

| Symptom | Root Cause | Source Location |
|---------|-----------|-----------------|
| **`ValueError: Configuration function foo must have 'hp: HP' as first parameter`** | Config function lacks `hp: HP` as first parameter | `validate_config_func_signature` in [`src/hypster/utils.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/utils.py) |
| **`UserWarning: Unknown or unreachable parameters`** with typo suggestions | Supplied key doesn't match any called parameter; library suggests alternatives | `_handle_unknown_parameters` in [`src/hypster/core.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/core.py) and `suggest_similar_names` in [`src/hypster/utils.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/utils.py) |
| **`HPCallError: param_name has already been defined`** | Duplicate parameter access, often via nesting | `_validate_name_not_called` in [`src/hypster/hp.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/hp.py) |
| **`HPCallError: prefix 'model' reserved`** | Nesting prefix collides with existing parameter name | `nest` method in [`src/hypster/hp.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/hp.py) |
| **Type errors or out-of-bounds values** | Validators reject supplied values | `_handle_single_value` / `_handle_multi_value` in [`src/hypster/hp.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/hp.py) |

## Step-by-Step Debugging Workflow

### Validate the Configuration Function Signature

Before parameter resolution begins, Hypster validates that your function accepts `hp: HP` as its first argument. If the signature is invalid, `instantiate` raises immediately.

```python
from hypster import instantiate

def my_config(hp):  # Must declare hp: HP as first parameter

    return hp.int(10, name="batch_size")

# This validates the signature and raises ValueError if incorrect

instantiate(my_config, values={})

```

### Inspect the Raw Values Dictionary

Hypster accepts both dotted keys (`"model.hidden_units": 128`) and nested dictionaries (`{"model": {"hidden_units": 128}}`). The utility `unflatten_dict` in [`src/hypster/utils.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/utils.py) converts dotted notation to nested structures for lookup. Verify your keys match the expected structure before debugging deeper.

### Check Which Parameters Were Actually Accessed

After execution, inspect `hp.called_params` to see exactly which parameters your function resolved. This set is updated by every public HP method including `int`, `select`, and `nest`.

```python
def inspect_cfg(hp):
    hp.int(10, name="batch_size")
    hp.float(0.001, name="learning_rate")

# Capture the HP instance to inspect internal state

result = instantiate(inspect_cfg, values={"batch_size": 32, "learning_rate": 0.01}, on_unknown="ignore")
print(result.called_params)  # Output: {'batch_size', 'learning_rate'}

```

### Identify Unknown Parameters with Strict Validation

By default, Hypster warns about unknown parameters. Force hard failures during debugging by setting `on_unknown="raise"`. The error message includes similarity scores from `difflib.SequenceMatcher` to catch typos.

```python
def cfg(hp):
    lr = hp.float(0.01, name="learning_rate")

values = {"lr": 0.005}  # Typo: should be "learning_rate"

try:
    instantiate(cfg, values=values, on_unknown="raise")
except ValueError as e:
    print(e)  # Shows: "Unknown or unreachable parameters: - 'lr': Did you mean 'learning_rate'? (similarity: 73%)"

```

### Debug Nesting and Namespace Collisions

Each `hp.nest(child, name="sub")` creates a new `HP` instance with its own `namespace_stack` while sharing the parent's `called_params`. Duplicate names across nesting boundaries raise `HPCallError`. Verify that nesting prefixes don't clash with existing parameter names, as enforced by the `nest` method in [`src/hypster/hp.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/hp.py).

```python
def child_cfg(hp):
    hp.int(128, name="hidden_units")

def parent_cfg(hp):
    hp.int(64, name="hidden_units")  # Error if not namespaced

    hp.nest(child_cfg, name="model")  # Creates namespace 'model'

```

### Enable Verbose Warnings

Ensure all `UserWarning` messages from `_handle_unknown_parameters` are visible by configuring the warnings filter at the start of your debugging session:

```python
import warnings
warnings.filterwarnings("always", category=UserWarning)

```

## Practical Code Examples

### Debugging Typos with Explicit Error Handling

```python
from hypster import instantiate

def training_config(hp):
    hp.int(32, name="batch_size")
    hp.float(0.001, name="learning_rate")
    hp.select(["adam", "sgd"], name="optimizer")

# Intentionally misspelled key to trigger suggestion logic

values = {"batch_size": 64, "learning_rate": 0.01, "optimzer": "adam"}

instantiate(training_config, values=values, on_unknown="raise")

```

### Inspecting Consumed vs. Supplied Parameters

```python
def model_cfg(hp):
    hp.int(128, name="hidden_units")
    hp.float(0.5, name="dropout")

values = {
    "hidden_units": 256,
    "dropout": 0.2,
    "unused_param": 999  # This will be flagged

}

# Use ignore to prevent exceptions, then check the returned object

config = instantiate(model_cfg, values=values, on_unknown="ignore")
print(f"Accessed: {config.called_params}")
print(f"Expected: {set(values.keys())}")

```

### Handling Duplicate Parameter Definitions

```python
def duplicate_cfg(hp):
    hp.int(1, name="seed")
    # This will raise HPCallError in _validate_name_not_called

    hp.int(42, name="seed")

try:
    instantiate(duplicate_cfg, values={})
except ValueError as e:
    print(f"Configuration error: {e}")  # "seed has already been defined"

```

## Summary

- **Hypster's pipeline** consists of `instantiate` creating an `HP` instance, executing your config function, and comparing supplied keys against `called_params` via `_handle_unknown_parameters`.
- **Unknown parameters** trigger warnings by default; use `on_unknown="raise"` for CI-friendly strict validation with typo suggestions powered by `difflib.SequenceMatcher` in [`src/hypster/utils.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/utils.py).
- **Signature validation** occurs in `validate_config_func_signature` in [`src/hypster/utils.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/utils.py) and requires `hp: HP` as the first parameter.
- **Duplicate parameters** across nesting boundaries raise `HPCallError` from [`src/hypster/hp.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/hp.py); each `nest()` call maintains a `namespace_stack` while sharing the parent's parameter registry.
- **Debugging tools** include inspecting `called_params`, enabling `warnings.filterwarnings("always")`, and using dotted or nested dictionary syntax interchangeably via `unflatten_dict`.

## Frequently Asked Questions

### Why does Hypster report my parameter as "unknown or unreachable"?

This occurs when a key in your `values` dictionary does not match any parameter accessed during configuration function execution. The `HP` class tracks accessed parameters in `called_params`, and `_handle_unknown_parameters` in [`src/hypster/core.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/core.py) compares this set against your inputs. If a key is present in `values` but never retrieved via `hp.int()`, `hp.float()`, or similar methods, Hypster flags it as potentially obsolete or misspelled, offering suggestions via `suggest_similar_names`.

### How can I see exactly which parameters my config function consumed?

After calling `instantiate`, access the `called_params` attribute on the returned configuration object. This `set` contains the fully-qualified names of all parameters resolved during execution, updated by every HP method in [`src/hypster/hp.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/hp.py). Compare this against your input `values` keys to identify unused or misspelled parameters during debugging.

### What causes the "parameter has already been defined" error?

The `HPCallError` originates in `_validate_name_not_called` within [`src/hypster/hp.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/hp.py) when your configuration function attempts to define the same parameter name twice. This commonly happens when nesting configurations that inadvertently share parameter names without proper namespacing, or when manually calling `hp.int()` or similar methods with duplicate `name` arguments in the same scope.

### How do I enable strict validation to catch typos in parameter names?

Pass `on_unknown="raise"` to the `instantiate` function in [`src/hypster/core.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/core.py). This forces Hypster to raise a `ValueError` instead of emitting a `UserWarning` when encountering keys in your `values` dictionary that don't match any called parameters. The error message includes similarity scores calculated by `difflib.SequenceMatcher` in [`src/hypster/utils.py`](https://github.com/gilad-rubin/hypster/blob/main/src/hypster/utils.py), making it ideal for catching typos in CI pipelines.