Repository navigation
Reject the invalid 'llm.model' config key with an actionable error - #503
Merged
codelion merged 1 commit intoOct 10, 2026
Conversation
dacite silently drops config keys that do not match a dataclass field, and LLMConfig has no 'model' field - models are configured via 'llm.models' or 'llm.primary_model'. A config using 'model:' therefore passed validation with an empty model ensemble, and every LLM call then failed with 'IndexError: list index out of range', retried forever, and flooded the log (issue algorithmicsuperintelligence#427). The reporter hit this by following the README's own provider examples, which used 'model:' in three places. Two-part fix: - Config.from_dict now raises ValueError when 'llm.model' is present, pointing at 'llm.primary_model' / 'llm.models'. The check lives in from_dict (not __post_init__) so internally constructed Config() objects keep their empty-default ensemble, matching the existing explicit-ValueError style of from_dict. - README provider examples (Gemini, Ollama/vLLM, OptiLLM) corrected from 'model:' to 'primary_model:', consistent with examples/*/config.yaml and the rest of the configuration docs. Fixes algorithmicsuperintelligence#427
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #427
Problem
LLMModelConfighas nomodelfield — models are configured via thellm.modelsarray orllm.primary_model. But dacite silently drops dict keys that don't match a dataclass field, so a config carryingllm.modelpassedConfig.from_dictwithout a whisper and producedllm.models == []. Downstream, every LLM call then died inLLMEnsemble._sample_modelwithIndexError: list index out of range, was retried, and flooded the log — exactly the reporter's "heaps of failed attempts: ERROR - LLM generation failed: list index out of range". The reporter's self-diagnosis in #427 is precise: withoutprimary_model, "the model is not recognized and an empty list is loaded as the model ensemble".The kicker: this is not a user reading carefully enough. The README itself teaches the broken spelling — the Google Gemini, Local Models (Ollama/vLLM), and OptiLLM provider examples all wrote
model:underllm:. Anyone copying an official example hit the crash; the reporter did.What
openevolve/config.py(Config.from_dict): raisesValueError("Invalid config key 'llm.model'. Use 'llm.primary_model' or the 'llm.models' array instead (see README configuration section).")whenllm.modelis present. Deliberate choices:from_dictalready has three explicitValueErrors (diff_patternregex,island_system_messagescount,programs_as_changes_descriptionrequires diff mode), so this matches the house style.modelwas never a valid field, so there is no backward-compatibility burden (unlike theprimary_modelalias precedent in__post_init__, which migrated a field that used to exist). A silent mapping would also leavemodel-plus-modelssemantics ambiguous.from_dict, not__post_init__: internally constructedConfig()objects never pass through a dict and legitimately start with an empty ensemble (that existing convention is documented in the__post_init__validation comment), so the dataclass path must keep acceptingmodels == [].isinstance(config_dict["llm"], dict)so a malformedllm:value still fails in dacite's existing type check instead of a confusing error from the new check.README.md: the three provider examples (Gemini ~line 359, Ollama/vLLM ~line 375, OptiLLM ~line 399) corrected frommodel:toprimary_model:, consistent withexamples/*/config.yamland the rest of the configuration docs. A sweep found no other baremodel:keys in README or example/config YAMLs (embedding_model:is a different, valid key).tests/test_llm_model_key_rejected.py: new unittest module (no LLM, ~0.001s):test_model_key_raises_helpful_error:Config.from_dict({"llm": {"model": ...}})raisesValueErrorwhose message namesprimary_modelandllm.models;test_model_key_with_other_keys_still_raises: still raises whenmodel:is mixed into an otherwise valid config (guards against a "only check bare dicts" false negative);test_primary_model_config_still_validandtest_models_array_config_still_valid: both documented spellings keep working (regression guards);test_code_constructed_config_unaffected:Config()keeps its empty-default ensemble — the internal initialization path is untouched.Red -> green evidence
Before the fix:
and the 3-line repro printed
BUG: silently accepted, models = []:After the fix:
Ran 5 tests in 0.001s ... OK, and the same repro now raisesValueError: Invalid config key 'llm.model'. Use 'llm.primary_model' or the 'llm.models' array instead (see README configuration section).Full suite:
OPENAI_API_KEY=test-key-for-unit-tests python -m unittest discover tests->Ran 579 tests in 33.177s ... OK(574 baseline + 5 new).Notes
primary_model; this PR makes that mistake impossible to miss instead of silently fatal.model:→primary_model:mistake for the Ollama README example only; this PR fixes all three examples plus adds the config-layer validation, so use primary_model instead of model for ollama config #451 would become redundant (happy to drop the Ollama hunk here if use primary_model instead of model for ollama config #451 lands first — at most a 1-line textual conflict).