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

  1. Change the config value at that namespace path to a table/object ([plugin.<namespace>])
  2. Check for TOML dotted-key conflicts that redefine a parent key as a scalar
  3. 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

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


AI-assisted analysis of p-e-w/heretic@bedb94ef11 (2026-08-29). Data as JSON: /api/errors/8c89a1f99e106f04. Report an issue: GitHub.