bmad-code-org/BMAD-METHOD · error · ValueError
--extra must be a JSON array of objects
Error message
--extra must be a JSON array of objects
What it means
pick_methods.py parses the `--extra` overlay (additional elicitation methods). The spec may be a JSON array literal or a path to a JSON file; after `json.loads` it must be a top-level JSON array. This error is raised when the JSON parsed successfully but the resulting value is not a list — it is an object, string, number, boolean, or null. The check is deliberately strict because downstream `merge_extra` iterates and indexes by `method_name`.
Source
Thrown at src/core-skills/bmad-advanced-elicitation/scripts/pick_methods.py:61
def load(file: Path) -> list[dict]:
# utf-8-sig: tolerate BOM-prefixed catalogs (Excel "CSV UTF-8", Notepad)
with open(file, newline="", encoding="utf-8-sig") as f:
rows = list(csv.DictReader(f))
for r in rows:
for k in FIELDS:
r.setdefault(k, "")
r[k] = (r.get(k) or "").strip()
return rows
def load_extra(spec: str) -> list[dict]:
"""Parse the --extra overlay: a JSON array literal or a path to a JSON file."""
text = spec if spec.lstrip().startswith("[") else Path(spec).read_text(encoding="utf-8-sig")
data = json.loads(text)
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}")
row = {k: str(item.get(k) or "").strip() for k in FIELDS}
row["code"] = str(item.get("code") or "").strip() # kept for traceability
rows.append(row)
return rows
def merge_extra(rows: list[dict], extras: list[dict]) -> list[dict]:
"""Extras replace a catalog row with the same method_name (case-insensitive),
otherwise append — so overrides can retune shipped methods or grow the catalog.
A replacement inherits the shipped row's num; appended extras get the next
free nums, so every merged method stays addressable by number."""
merged = list(rows)
index = {r["method_name"].lower(): i for i, r in enumerate(merged)}
for e in extras:View on GitHub (pinned to b70486b9bd)
Solutions
- Wrap a single object in an array: `--extra '[{"method_name":"...","category":"..."}]'`.
- If pointing at a file, open it and confirm the top-level character is `[`.
- Validate the JSON with `python -m json.tool` and check the root type before passing it to `--extra`.
- Build the overlay from `customize.toml`'s `additional_methods` via the project's own emitter rather than hand-editing.
Example fix
# before
--extra '{"method_name":"Devil's Advocate","category":"challenge"}'
# after: wrap in an array
--extra '[{"method_name":"Devil's Advocate","category":"challenge","description":"...","output_pattern":"..."}]' Defensive patterns
Strategy: validation
Validate before calling
import json
spec = '{...}' # or file contents
data = json.loads(spec if spec.lstrip().startswith('[') else open(path).read())
assert isinstance(data, list), '--extra must be a JSON array of objects' Type guard
def is_json_array(spec: str) -> bool:
try:
v = json.loads(spec)
except json.JSONDecodeError:
return False
return isinstance(v, list) Try / catch
try:
extras = load_extra(args.extra)
except ValueError as e:
print(f"error: {e}", file=sys.stderr); sys.exit(2) Prevention
- Always wrap --extra content in [ ], even for a single method.
- Validate the overlay with python -m json.tool before passing it.
- Prefer generating the overlay from customize.toml's additional_methods over hand-writing JSON.
When it happens
Trigger: Calling with `--extra '{"method_name": "..."}'` (a single object, not wrapped in `[ ]`), `--extra methods.json` where the file contains a JSON object or a bare string, or a YAML-style document that happens to be valid JSON but is a mapping.
Common situations: Hand-writing one extra method and forgetting the surrounding brackets; exporting a single record from another tool that serializes as an object; a templating step that emits `{}` instead of `[{...}]`.
Related errors
- each --extra entry must be a JSON object, got: {item!r}
- --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/c49ae5467e8622a0.
Report an issue: GitHub.