bmad-code-org/BMAD-METHOD · error · ConfigError

TOML layer did not parse to a table: {path}

Error message

TOML layer did not parse to a table: {path}

What it means

Defensive guard at the end of `load_toml`: after a successful `tomllib.load`, the result must be a `dict` (a TOML top-level table). `tomllib` always returns a dict for well-formed TOML, so in practice this is nearly unreachable — it would only fire on a future/alternate parser that returns a non-dict root, or if `load_toml` is repurposed with a parser that can yield a bare array. Treat it as an invariant assertion, not an expected user error.

Source

Thrown at src/scripts/config_utils.py:33


def load_toml(path: Path, *, required: bool = False) -> dict[str, Any]:
    """Load a TOML table, allowing absence only for optional layers."""
    if not path.exists():
        if required:
            raise ConfigError(f"required TOML file not found: {path}")
        return {}
    if not path.is_file():
        raise ConfigError(f"TOML layer is not a file: {path}")
    try:
        with path.open("rb") as stream:
            parsed = tomllib.load(stream)
    except tomllib.TOMLDecodeError as error:
        raise ConfigError(f"failed to parse {path}: {error}") from error
    except OSError as error:
        raise ConfigError(f"failed to read {path}: {error}") from error
    if not isinstance(parsed, dict):
        raise ConfigError(f"TOML layer did not parse to a table: {path}")
    return parsed


def _detect_keyed_merge_field(items: list[Any]) -> str | None:
    if not items or not all(isinstance(item, dict) for item in items):
        return None
    for candidate in _KEYED_MERGE_FIELDS:
        if all(candidate in item for item in items):
            for item in items:
                value = item[candidate]
                if not isinstance(value, str):
                    raise ConfigError(
                        f"keyed array identifier `{candidate}` must be a string, "
                        f"got {type(value).__name__}"
                    )
                if not value:
                    raise ConfigError(
                        f"keyed array identifier `{candidate}` must not be empty"

View on GitHub (pinned to b70486b9bd)

Solutions

  1. Confirm you are using stdlib `tomllib` (Python 3.11+) and not a third-party substitute.
  2. Ensure the file genuinely has key/value tables at the top level, not a bare TOML array document.
  3. If you wrapped the parser, make sure it still returns a dict root.
Defensive patterns

Strategy: validation

Validate before calling

import tomllib
parsed = tomllib.load(open(path,'rb'))
assert isinstance(parsed, dict), f'TOML layer did not parse to a table: {path}'

Type guard

def parses_to_table(path) -> bool:
    return isinstance(tomllib.load(open(path,'rb')), dict)

Try / catch

try:
    load_toml(path, required=required)
except ConfigError as e:
    print(f"error: {e}", file=sys.stderr); sys.exit(2)

Prevention

When it happens

Trigger: Swapping `tomllib` for a parser that returns a list for a top-level TOML array; an internal refactor that bypasses the table contract; a corrupt parse path that returns None.

Common situations: Essentially never in normal use. If it appears, suspect a custom monkeypatch of `tomllib` or a hand-edited `config_utils.py`.

Related errors


AI-assisted analysis of bmad-code-org/BMAD-METHOD@b70486b9bd (2026-08-13). Data as JSON: /api/errors/f22b33dead1f99a7. Report an issue: GitHub.