p-e-w/heretic · error · TypeError
{self.__class__.__name__}.settings must be an instance of {s
Error message
{self.__class__.__name__}.settings must be an instance of {settings_model.__name__} What it means
The plugin declares a settings model, settings were provided, but they are not an instance of that exact pydantic model class. Plugin.__init__ raises TypeError to guarantee plugins only ever see settings validated against their declared schema.
Source
Thrown at src/heretic/plugin.py:225
Defaults to False; override to True in your plugin class if any of the
above DO NOT apply.
"""
return False
def __init__(
self, *, heretic_settings: HereticSettings, settings: BaseModel | None = None
):
# Plugins that declare a settings schema should always receive
# validated plugin settings from the evaluator.
settings_model = self.__class__.get_settings_model()
if settings_model is not None:
if settings is None:
raise ValueError(
f"{self.__class__.__name__} requires settings to be validated"
)
if not isinstance(settings, settings_model):
raise TypeError(
f"{self.__class__.__name__}.settings must be an instance of "
f"{settings_model.__name__}"
)
self.settings = settings
self.heretic_settings = heretic_settings
@classmethod
def validate_contract(cls) -> None:
"""
Validate the plugin contract.
- Plugins must not define a constructor (`__init__`). Initialization is
handled by `Plugin.__init__` and an optional `init(ctx)` method.
- Plugin subclasses may define `settings: <BaseModelSubclass>` to declare a settings schema.
"""
if "__init__" in cls.__dict__:
raise TypeError(
f"{cls.__name__} must not define __init__(). "View on GitHub (pinned to bedb94ef11)
Solutions
- Construct settings with the exact model named in the error: SettingsModel(**config_dict).
- Validate your TOML table through the evaluator's normal path so it instantiates the right model.
- If you deliberately changed the schema, update get_settings_model()/the annotation and all construction sites together.
Example fix
# before
plugin = MyScorer(heretic_settings=hs, settings={"threshold": 0.5})
# after
plugin = MyScorer(heretic_settings=hs, settings=MyScorerSettings(threshold=0.5)) Defensive patterns
Strategy: type-guard
Validate before calling
model = MyScorer.get_settings_model()
assert isinstance(raw_settings, model), f"expected {model.__name__}, got {type(raw_settings).__name__}" Type guard
def has_valid_settings(plugin: object, model: type) -> bool:
return isinstance(getattr(plugin, "settings", None), model) Try / catch
try:
plugin = MyScorer(heretic_settings=hs, settings=raw)
except TypeError as e:
sys.exit(f"{e} — construct settings via {MyScorer.get_settings_model()}(**cfg)") Prevention
- Always instantiate the exact settings model, never pass dicts.
- When refactoring settings models, update all construction sites.
- Let the evaluator build settings from TOML instead of hand-constructing them.
When it happens
Trigger: Passing a raw dict, a different BaseModel subclass, or another plugin's settings instance into __init__; a custom evaluator wiring settings from the wrong [namespace] table; subclassing a plugin but reusing the parent's settings class while the evaluator supplies the child's.
Common situations: Refactors that renamed or replaced the settings model while old callers construct the old type; tests passing mocks/dicts; two plugins with similarly named settings models getting crossed in a config.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- {self.__class__.__name__} requires settings to be validated
- {cls.__name__}.settings must not be Optional; use a non-opti
- {cls.__name__}.settings must be annotated with a pydantic.Ba
- cannot be empty or whitespace
- '.' is not allowed
AI-assisted analysis of p-e-w/heretic@bedb94ef11 (2026-08-29).
Data as JSON: /api/errors/843a35c586ce46b8.
Report an issue: GitHub.