bmad-code-org/BMAD-METHOD · error · ConfigError
failed to parse {path}: {error}
Error message
failed to parse {path}: {error} What it means
`load_toml` catches `tomllib.TOMLDecodeError` and re-raises it as `ConfigError` with the file path and the underlying parse error. It means the TOML file was read from disk but its syntax is invalid — unclosed string, duplicate keys, a bare value, an unterminated table header, a malformed array, or a non-TOML file (YAML/JSON) that was placed there by mistake.
Source
Thrown at src/scripts/config_utils.py:29
"""Raised when a present configuration layer cannot be used safely."""
_KEYED_MERGE_FIELDS = ("code", "id")
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__}"View on GitHub (pinned to b70486b9bd)
Solutions
- Read the full error text after the colon — it includes the line/column of the parse failure.
- Open the file at that line and fix the syntax (quote string values, close brackets, deduplicate keys).
- Validate with a TOML linter: `python -c "import tomllib;tomllib.load(open('<path>','rb'))"`.
- If the file is actually YAML/JSON, convert it to TOML or move it to the correct extension/layer.
Example fix
# before (config.toml) [project] name = BMAD # bare value -> TOMLDecodeError version = 1.0. # trailing dot # after [project] name = "BMAD" version = "1.0"
Defensive patterns
Strategy: try-catch
Validate before calling
import tomllib
try:
tomllib.load(open(path,'rb'))
except tomllib.TOMLDecodeError as e:
raise SystemExit(f'TOML syntax error: {e}') Try / catch
try:
load_toml(path, required=required)
except ConfigError as e:
print(f"error: {e}", file=sys.stderr); sys.exit(2) Prevention
- Edit TOML with a TOML-aware editor that flags syntax errors live.
- Quote string values; never leave conflict markers in config.
- Run python -m tomllib (or a linter) over config in CI.
When it happens
Trigger: A hand-edited `_bmad/config.toml` with a syntax slip (`name = BMAD` instead of `name = "BMAD"`); a YAML or JSON file saved with a `.toml` extension; a merge conflict marker left in the file; an unterminated multiline string.
Common situations: Editing config without a TOML-aware editor; copying a snippet from docs that used a different config language; unresolved `<<<<<<<` conflict markers after a git merge.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- required TOML file not found: {path}
- TOML layer is not a file: {path}
- TOML layer did not parse to a table: {path}
- keyed array identifier `{candidate}` must be a string, got {
- keyed array identifier `{candidate}` must not be empty
AI-assisted analysis of bmad-code-org/BMAD-METHOD@b70486b9bd (2026-08-13).
Data as JSON: /api/errors/a78019857c095ca7.
Report an issue: GitHub.