bmad-code-org/BMAD-METHOD · error · ConfigError
required TOML file not found: {path}
Error message
required TOML file not found: {path} What it means
config_utils.py's `load_toml` is the shared loader for every TOML config layer. When called with `required=True` and the path does not exist, it raises `ConfigError`. Required layers in this codebase are `_bmad/config.toml` (central config) and a skill's `customize.toml`; optional layers like `config.user.toml` simply return `{}` when absent. The error means a mandatory configuration file the tool needs to operate is missing.
Source
Thrown at src/scripts/config_utils.py:21
from __future__ import annotations
import tomllib
from pathlib import Path
from typing import Any, Iterable
class ConfigError(ValueError):
"""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 NoneView on GitHub (pinned to b70486b9bd)
Solutions
- Confirm the file at the reported path actually exists: `ls -la <path>`.
- Run the project's init/bootstrap command to scaffold `_bmad/config.toml` and the skill `customize.toml`.
- Check that the working directory or `--project-root` points at the project that owns the `_bmad` folder.
- If the file genuinely should be optional for your flow, call `load_toml(path)` without `required=True` (or adjust the caller).
Example fix
# before: load_toml(Path('_bmad/config.toml'), required=True) -> file absent
# fix: create the required config
mkdir -p _bmad && cat > _bmad/config.toml <<'EOF'
[project]
name = "my-project"
EOF Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
path = Path('_bmad/config.toml')
assert path.is_file(), f'required TOML file not found: {path}'
load_toml(path, required=True) Type guard
def required_toml_present(path) -> bool:
return Path(path).is_file() Try / catch
from config_utils import ConfigError
try:
load_toml(path, required=True)
except ConfigError as e:
print(f"error: {e}", file=sys.stderr); sys.exit(2) Prevention
- Run the project's init step to scaffold required config before any render.
- Always run tools from the project root that owns _bmad.
- In CI, assert _bmad/config.toml exists in a pre-check before invoking tools.
When it happens
Trigger: Running `render_skill` (or any tool calling `load_central_config` / `load_customization`) in a project that has no `_bmad/config.toml`; invoking a skill outside its installed directory so `customize.toml` is not found; a path typo or a misconfigured project root.
Common situations: A fresh checkout that skipped the BMAD init step; running from the wrong working directory; a renamed or moved `_bmad` folder; CI running in a shallow clone that excluded the config tree.
Related errors
- TOML layer is not a file: {path}
- failed to parse {path}: {error}
- failed to read {path}: {error}
- TOML layer did not parse to a table: {path}
- keyed array identifier `{candidate}` must be a string, got {
AI-assisted analysis of bmad-code-org/BMAD-METHOD@b70486b9bd (2026-08-13).
Data as JSON: /api/errors/5e5dad3ad359fd01.
Report an issue: GitHub.