[6.11.0] config_utils.py: keyed-array merge raises ConfigError on non-string `code`/`id` values instead of falling back — regression vs 6.10, aborts the entire config load
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 78/100
Research direction
Read _bmad/scripts/config_utils.py, especially _detect_keyed_merge_field around line 45, then run the structural_merge reproduction from the issue. Make non-string candidate values skip to the next candidate and use append semantics when none qualifies, while retaining validation for keyed arrays whose values are all strings.
Written by the indexing model from the issue text.
Description
Severity: medium-high — one user-authored array in any config layer breaks resolve_config, resolve_customization, and render_skill for every skill at once
Version: bmad-method 6.11.0
Summary
_bmad/scripts/config_utils.py's _detect_keyed_merge_field (line ~45) raises as soon as all items of an array-of-tables share a code (or id) field whose value is non-string:
ConfigError: keyed array identifier `code` must be a string, got int
The raise sits inside the first candidate's validation loop, so it fires even when every item also carries a perfectly valid string id — the detector never advances to the next candidate key, and never reaches the append fallback.
6.10's detector (resolve_config.py, _detect_keyed_merge_field, if all(item.get(candidate) is not None for item in items): return candidate) had no type check and merged the same inputs without error. So legal TOML that worked under 6.10 — e.g. HTTP-status tables [{code = 200, ...}], numeric-id rosters — now aborts load_central_config/load_customization entirely, which takes down all three consumer scripts for every skill, not just the one owning the array.
Repro
from config_utils import structural_merge
structural_merge({"arr": [{"code": 1, "id": "a", "v": 1}]},
{"arr": [{"code": 2, "id": "b", "v": 2}]})
# ConfigError: keyed array identifier `code` must be a string, got int
# (never tries "id", never falls back to append)
Suggested fix
Treat a non-string candidate value as "this candidate is not the merge key": skip to the next candidate, and fall back to append semantics when no candidate qualifies — matching 6.10's accepting behavior while keeping the new validation for arrays that genuinely opt into keyed merge (all values present and strings).
- Dominant language
- Python
- Stars
- 53.2k
- Forks
- 6k
- Avg merge
- 4h 26m
- Merged PRs (30d)
- 86
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from bmad-code-org/BMAD-METHOD
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
bmad-code-org/BMAD-METHOD#2907 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
bmad-code-org/BMAD-METHOD#2885 · 1 comment ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
bmad-code-org/BMAD-METHOD#2869 ·
-
Difficulty 1/5 1-3 hours Newbie friendliness 88/100
bmad-code-org/BMAD-METHOD#2792 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
bmad-code-org/BMAD-METHOD#2726 ·
All issues in bmad-code-org/BMAD-METHOD
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100