TheAlgorithms/Python · error · ValueError

{var_name} all keys must be strings

Error message

{var_name} all keys must be strings

What it means

Raised by viterbi's _validate_dict when the object is a dict but one or more keys is not a string. Probability tables are keyed by state and observation names (symbols), so integer or float keys like {2: 0.5} are rejected. The same validator runs on nested dicts (rows of the transition/emission tables) with nested=True.

Source

Thrown at dynamic_programming/viterbi.py:367

    >>> _validate_dict({"a": 8}, "mock_name", dict)
    Traceback (most recent call last):
            ...
    ValueError: mock_name all values must be dict
    >>> _validate_dict({2: 0.5}, "mock_name",float, True)
    Traceback (most recent call last):
            ...
    ValueError: mock_name all keys must be strings
    >>> _validate_dict({"b": 4}, "mock_name", float,True)
    Traceback (most recent call last):
            ...
    ValueError: mock_name nested dictionary all values must be float
    """
    if not isinstance(_object, dict):
        msg = f"{var_name} must be a dict"
        raise ValueError(msg)
    if not all(isinstance(x, str) for x in _object):
        msg = f"{var_name} all keys must be strings"
        raise ValueError(msg)
    if not all(isinstance(x, value_type) for x in _object.values()):
        nested_text = "nested dictionary " if nested else ""
        msg = f"{var_name} {nested_text}all values must be {value_type.__name__}"
        raise ValueError(msg)


if __name__ == "__main__":
    from doctest import testmod

    testmod()

View on GitHub (pinned to f5988cc097)

Solutions

  1. Key every probability dict by the string state/symbol names used in states_space and observations_space: {'rainy': 0.6, 'sunny': 0.4}.
  2. When converting from matrix indices, map through the names: {states[i]: {states[j]: m[i][j] ...}}.
  3. Add a self-check that set(initial_probabilities) == set(states_space).

Example fix

# before
initial_p = {0: 0.6, 1: 0.4}  # ValueError: keys must be strings

# after
states = ['rainy', 'sunny']
initial_p = {'rainy': 0.6, 'sunny': 0.4}
Defensive patterns

Strategy: validation

Validate before calling

def keys_match(table: dict, names: list[str]) -> bool:
    return all(isinstance(k, str) for k in table) and set(table) == set(names)

Type guard

def str_keyed(d: object) -> TypeGuard[dict[str, object]]:
    return isinstance(d, dict) and all(isinstance(k, str) for k in d)

Prevention

When it happens

Trigger: Passing initial_probabilities={0: 0.6, 1: 0.4} with integer state codes; a transition row {'rainy': {0: 0.7}}; keys loaded from JSON where someone used numeric ids as object keys and they stayed ints after processing.

Common situations: Building HMM tables programmatically with enumerate() ints as keys; converting from a matrix representation where indices leak into dict keys; mixing a string state list with numeric-keyed probability tables (the two never match).

Related errors


AI-assisted analysis of TheAlgorithms/Python@f5988cc097 (2026-08-14). Data as JSON: /api/errors/96b6c7bdc6add0ea. Report an issue: GitHub.