p-e-w/heretic · error · TypeError
Plugin namespace [{namespace}] must be a table/object, got {
Error message
Plugin namespace [{namespace}] must be a table/object, got {type(cur).__name__} What it means
get_plugin_namespace walks the config table path segment by segment for a plugin's namespace. If the value found at that path exists but is not a table/dict (e.g. a string or number), the structure is invalid, so it raises TypeError naming the namespace path and the offending type.
Source
Thrown at src/heretic/plugin.py:40
T = TypeVar("T")
def get_plugin_namespace(
model_extra: dict[str, Any] | None, namespace: str
) -> dict[str, Any]:
"""
Returns the config dict from the `[<namespace>]` TOML table.
"""
cur: Any = model_extra
for part in namespace.split("."):
if not isinstance(cur, dict):
return {}
cur = cur.get(part)
if cur is None:
return {}
if not isinstance(cur, dict):
raise TypeError(
f"Plugin namespace [{namespace}] must be a table/object, got {type(cur).__name__}"
)
return cur
def is_builtin_plugin(name: str) -> bool:
"""
Whether the plugin name refers to a plugin that ships with Heretic.
Only built-in plugins can be resolved when reproducing a model, so external
plugins (file paths or third-party import paths) disable the reproducibility
offer during upload.
"""
return name.startswith("heretic.scorers.")
def load_plugin(
name: str,View on GitHub (pinned to bedb94ef11)
Solutions
- Change the config value at that namespace path to a table/object ([plugin.<namespace>])
- Check for TOML dotted-key conflicts that redefine a parent key as a scalar
- Print/inspect the loaded config to confirm the type at the reported path
Example fix
// before (config.toml) myplugin = "enabled" // after (config.toml) [myplugin] enabled = true
Defensive patterns
Strategy: type-guard
Validate before calling
import tomllib
with open("config.toml", "rb") as f:
cfg = tomllib.load(f)
ns = cfg.get("plugins", {}).get("myplugin")
if ns is not None and not isinstance(ns, dict):
raise TypeError("plugins.myplugin must be a table") Type guard
def is_table(value) -> bool:
return value is None or isinstance(value, dict) Try / catch
try:
settings = get_plugin_namespace(config, "myplugin")
except TypeError as e:
logger.error("Bad config structure: %s", e)
raise SystemExit(1) Prevention
- Use explicit [section] headers instead of assigning scalars for plugin namespaces
- Avoid TOML dotted-key patterns that can redefine parents as scalars
- Validate config structure with a schema (pydantic/jsonschema) before use
When it happens
Trigger: A config.toml section expected to be a table is instead a scalar — e.g. writing `refusal = "on"` instead of `[plugins.refusal]`, or a dotted key collision where an intermediate path resolves to a non-table value.
Common situations: Typos in config.toml turning a section header into a key, TOML dotted-key conflicts (defining both a.b = 1 and [a.b.c]), or JSON configs where an object was replaced by a string.
Related errors
- cannot be empty or whitespace
- '.' is not allowed
- whitespace is not allowed
- No scorers configured. Set 'scorers' in config.toml
- Duplicate scorer instance name: {scorer_key}. Give each inst
AI-assisted analysis of p-e-w/heretic@bedb94ef11 (2026-08-29).
Data as JSON: /api/errors/8c89a1f99e106f04.
Report an issue: GitHub.