nexu-io/open-design · error · SystemExit
[CompetitorsPlan] Invalid JSON: {exc}
Error message
[CompetitorsPlan] Invalid JSON: {exc} What it means
After loading the plan string (inline or from file), the sanitizer calls json.loads(plan_str). On json.JSONDecodeError it writes `[CompetitorsPlan] Invalid JSON: <exc>` and raises SystemExit(2). The captured exception carries the line/column, which is shown to the user.
Source
Thrown at design-templates/last30days/scripts/last30days.py:324
Accepts inline JSON or a file path (matches --plan). Returns {} on None/empty.
Validation: top-level must be a dict; each value must be a dict. Unknown fields
in entry values log a warning but do not abort. Invalid JSON or non-dict shape
raises SystemExit(2) with a clear stderr message.
"""
if not raw:
return {}
plan_str = raw
if os.path.isfile(plan_str):
try:
plan_str = open(plan_str).read()
except OSError as exc:
sys.stderr.write(f"[CompetitorsPlan] Cannot read plan file: {exc}\n")
raise SystemExit(2)
try:
parsed = json.loads(plan_str)
except json.JSONDecodeError as exc:
sys.stderr.write(f"[CompetitorsPlan] Invalid JSON: {exc}\n")
raise SystemExit(2)
if not isinstance(parsed, dict):
sys.stderr.write(
f"[CompetitorsPlan] Top-level must be a dict of "
f"{{entity: {{targeting}}}}, got {type(parsed).__name__}\n"
)
raise SystemExit(2)
known_fields = {
"x_handle", "x_related", "subreddits",
"github_user", "github_repos", "context",
}
normalized: dict[str, dict] = {}
for entity, entry in parsed.items():
if not isinstance(entry, dict):
sys.stderr.write(
f"[CompetitorsPlan] Entry for {entity!r} must be a dict, "
f"got {type(entry).__name__}; skipping.\n"
)
continueView on GitHub (pinned to 5be4028344)
Solutions
- Validate the JSON independently: `python3 -m json.tool <path>` or `jq . <path>`.
- Fix the reported line/column from the interpolated exception.
- Use double quotes for all keys and string values; remove trailing commas.
- Ensure the file is pure JSON (no leading YAML front-matter, no Markdown fences).
Example fix
# before
--plan '{"acme": {x_handle: "acme",},}'
# after
--plan '{"acme": {"x_handle": "acme"}}' Defensive patterns
Strategy: validation
Validate before calling
import json
try:
parsed = json.loads(plan_str)
except json.JSONDecodeError as exc:
raise ValueError(f'plan is not valid JSON: {exc}') from exc Prevention
- Validate with `python3 -m json.tool plan.json` or `jq . plan.json` before running.
- Generate plan JSON programmatically rather than hand-editing.
When it happens
Trigger: `--plan '{"acme":'` (truncated), trailing comma, single quotes used instead of double quotes, a control character, or a file whose content is YAML/Markdown rather than JSON.
Common situations: Hand-writing JSON and forgetting a brace; copy-paste that dropped the closing bracket; passing a YAML plan by mistake; BOM or smart-quotes from a word processor.
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
- [CompetitorsPlan] Top-level must be a dict of {entity: {targ
- [CompetitorsPlan] Cannot read plan file: {exc}
- [Competitors] --competitors-list is empty.\n
- [Competitors] --competitors must be >= {COMPETITORS_MIN} (go
- Unknown search source: {source}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/f484b99a943bcc3a.
Report an issue: GitHub.