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
- Key every probability dict by the string state/symbol names used in states_space and observations_space: {'rainy': 0.6, 'sunny': 0.4}.
- When converting from matrix indices, map through the names: {states[i]: {states[j]: m[i][j] ...}}.
- 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
- Build tables via {states[i]: ...} so names, not indices, become keys.
- Assert set(initial_probabilities) == set(states_space) in tests.
- Avoid numeric keys surviving from matrix-to-dict conversions.
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
- {var_name} must be a list
- {var_name} must be a list of strings
- {var_name} must be a dict
- {var_name} {nested_text}all values must be {value_type.__nam
- There's an empty parameter
AI-assisted analysis of TheAlgorithms/Python@f5988cc097 (2026-08-14).
Data as JSON: /api/errors/96b6c7bdc6add0ea.
Report an issue: GitHub.