langchain-ai/deepagents · error · TypeError

{name} must be a table

Error message

{name} must be a table

What it means

When writing the TOML config, _require_table validates that each top-level section being updated is a table (dict). If a parsed TOML value with the given name is a scalar/array instead of a table, it raises TypeError('{name} must be a table'). The library throws this to prevent corrupting a config where, say, `[startup]` was hand-edited into a plain string.

Source

Thrown at libs/code/deepagents_code/model_config.py:4363

    """Read-modify-write one entry in `[effort.by_model]`.

    Args:
        model_spec: Model in `provider:model` format.
        effort: Reasoning effort label to save, or `None` to clear it.
        config_path: Path to config file.

    Returns:
        `True` if the update succeeded, `False` if it failed.
    """
    if config_path is None:
        config_path = DEFAULT_CONFIG_PATH
    if effort is None and not config_path.exists():
        return True

    def _require_table(value: object, name: str) -> dict:
        if not isinstance(value, dict):
            msg = f"{name} must be a table"
            raise TypeError(msg)
        return value

    try:
        with _config_write_lock:
            config_path.parent.mkdir(parents=True, exist_ok=True)
            if config_path.exists():
                with config_path.open("rb") as f:
                    data = tomllib.load(f)
            else:
                data = {}

            effort_section = _require_table(data.setdefault("effort", {}), "[effort]")
            by_model = _require_table(
                effort_section.setdefault("by_model", {}), "[effort.by_model]"
            )

            if effort is None:
                if model_spec not in by_model:

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Open the config file printed/located at config_path and rewrite the offending entry as a TOML table: `startup = "auto"` → `[startup]` with keys beneath it.
  2. If the file is badly corrupted, back it up and delete/recreate it so the library regenerates a valid config.
  3. Validate the TOML with a parser (`python -c "import tomllib;print(tomllib.load(open('<path>','rb')))"`) before saving again.

Example fix

// before (invalid TOML section)
startup = "auto"
// after
[startup]
recent = "auto"
Defensive patterns

Strategy: validation

Validate before calling

import tomllib
with open(config_path, "rb") as fh:
    cfg = tomllib.load(fh)
bad = [k for k, v in cfg.items() if k in {"startup"} and not isinstance(v, dict)]
if bad:
    raise SystemExit(f"Config sections must be TOML tables, fix: {bad}")

Try / catch

try:
    save_recent_startup_mode(mode)
except TypeError:
    # back up and let the library rebuild a valid config
    config_path.rename(config_path.with_suffix(".toml.bak"))
    save_recent_startup_mode(mode)

Prevention

When it happens

Trigger: Any config-saving path (e.g. saving startup/recent settings or sort order) when the existing config file defines the target section name as a non-table TOML value, such as `startup = "auto"` instead of `[startup]`.

Common situations: Manual hand-editing of config.toml with wrong syntax (key=value instead of a [section] header); a previous buggy writer or another tool flattened the section; copy-pasting a scalar over a section.

Related errors


AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29). Data as JSON: /api/errors/82950db788c581f9. Report an issue: GitHub.