bmad-code-org/BMAD-METHOD · error · ValueError
each --extra entry must be a JSON object, got: {item!r}
Error message
each --extra entry must be a JSON object, got: {item!r} What it means
brain.py confirms each element of the techniques overlay array is a dict and raises with the offending `{item!r}`. The next line reads `item.get("category")`, `.get("technique_name")`, etc., which only dicts support. A scalar/null element would otherwise crash with `AttributeError` mid-build.
Source
Thrown at src/core-skills/bmad-brainstorming/scripts/brain.py:76
for k in FIELDS:
r.setdefault(k, "")
r[k] = (r.get(k) or "").strip()
return rows
def load_extra(file: Path) -> list[dict]:
"""Merge-in techniques from a JSON overlay — a list of
{category, technique_name, description[, detail]} objects. This is how
customize.toml's `additional_techniques` become first-class across *every*
subcommand (categories/list/random/show/html), so the browse page and
category draws include them too, not just the in-chat flows."""
data = json.loads(file.read_text(encoding="utf-8-sig"))
if not isinstance(data, list):
raise ValueError("--extra must be a JSON array of objects")
rows = []
for item in data:
if not isinstance(item, dict):
raise ValueError(f"each --extra entry must be a JSON object, got: {item!r}")
rows.append({
"category": str(item.get("category", "")).strip(),
"technique_name": str(item.get("technique_name", "")).strip(),
"description": str(item.get("description", "")).strip(),
"detail": str(item.get("detail") or "").strip(),
"provenance": str(item.get("provenance") or "").strip(),
"good_for": str(item.get("good_for") or "").strip(),
"audience": str(item.get("audience") or "").strip(),
})
return rows
def merge_extra(rows: list[dict], extras: list[dict]) -> list[dict]:
"""Extras replace a catalog row with the same technique_name (case-insensitive),
otherwise append — the same overlay semantics as pick_methods.py, so
customize.toml additional_* entries behave identically across sibling skills."""
merged = list(rows)
index = {r["technique_name"].lower(): i for i, r in enumerate(merged)}View on GitHub (pinned to b70486b9bd)
Solutions
- Find the element shown in `{item!r}` and turn it into an object with at least `category`, `technique_name`, and `description`.
- Lint every element: `python -c "import json,sys;[print(i,type(x).__name__) for i,x in enumerate(json.load(open(sys.argv[1])))]" file.json`.
- Edit the overlay through a typed authoring path rather than raw JSON.
Example fix
# before
[
"SCAMPER",
{"category":"divergent","technique_name":"Six Hats","description":"..."}
]
# after
[
{"category":"divergent","technique_name":"SCAMPER","description":"..."},
{"category":"divergent","technique_name":"Six Hats","description":"..."}
] Defensive patterns
Strategy: type-guard
Validate before calling
import json
data = json.loads(Path(file).read_text(encoding='utf-8-sig'))
assert isinstance(data, list) and all(isinstance(x, dict) for x in data), \
'each --extra entry must be a JSON object' Type guard
def is_object_array(v: object) -> bool:
return isinstance(v, list) and all(isinstance(x, dict) for x in v) Try / catch
try:
extras = load_extra(Path(args.extra))
except ValueError as e:
print(f"error: {e}", file=sys.stderr); sys.exit(2) Prevention
- Lint each element before running.
- Use a JSON schema requiring array-of-object.
- Author techniques via a typed editor, not raw JSON.
When it happens
Trigger: An array that mixes objects with a bare string, number, boolean, or null: `["SCAMPER", {"category":"..."}]`.
Common situations: A note accidentally dropped into the array; a truncated entry missing its braces; a generator that emits technique names as strings.
Related errors
- --extra must be a JSON array of objects
- --extra must be a JSON array of objects
- each --extra entry must be a JSON object, got: {item!r}
- unparseable date: {raw!r} (want YYYY[-MM[-DD]])
- 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/aa1c79ac878cf10c.
Report an issue: GitHub.