{"record":{"id":"f484b99a943bcc3a","repo":"nexu-io/open-design","slug":"competitorsplan-invalid-json-exc","errorCode":null,"errorMessage":"[CompetitorsPlan] Invalid JSON: {exc}","messagePattern":"\\[CompetitorsPlan\\] Invalid JSON: (.+?)","errorType":"console","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"design-templates/last30days/scripts/last30days.py","lineNumber":324,"sourceCode":"    Accepts inline JSON or a file path (matches --plan). Returns {} on None/empty.\n    Validation: top-level must be a dict; each value must be a dict. Unknown fields\n    in entry values log a warning but do not abort. Invalid JSON or non-dict shape\n    raises SystemExit(2) with a clear stderr message.\n    \"\"\"\n    if not raw:\n        return {}\n    plan_str = raw\n    if os.path.isfile(plan_str):\n        try:\n            plan_str = open(plan_str).read()\n        except OSError as exc:\n            sys.stderr.write(f\"[CompetitorsPlan] Cannot read plan file: {exc}\\n\")\n            raise SystemExit(2)\n    try:\n        parsed = json.loads(plan_str)\n    except json.JSONDecodeError as exc:\n        sys.stderr.write(f\"[CompetitorsPlan] Invalid JSON: {exc}\\n\")\n        raise SystemExit(2)\n    if not isinstance(parsed, dict):\n        sys.stderr.write(\n            f\"[CompetitorsPlan] Top-level must be a dict of \"\n            f\"{{entity: {{targeting}}}}, got {type(parsed).__name__}\\n\"\n        )\n        raise SystemExit(2)\n    known_fields = {\n        \"x_handle\", \"x_related\", \"subreddits\",\n        \"github_user\", \"github_repos\", \"context\",\n    }\n    normalized: dict[str, dict] = {}\n    for entity, entry in parsed.items():\n        if not isinstance(entry, dict):\n            sys.stderr.write(\n                f\"[CompetitorsPlan] Entry for {entity!r} must be a dict, \"\n                f\"got {type(entry).__name__}; skipping.\\n\"\n            )\n            continue","sourceCodeStart":306,"sourceCodeEnd":342,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/design-templates/last30days/scripts/last30days.py#L306-L342","documentation":"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.","triggerScenarios":"`--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.","commonSituations":"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.","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)."],"exampleFix":"# before\n--plan '{\"acme\": {x_handle: \"acme\",},}'\n# after\n--plan '{\"acme\": {\"x_handle\": \"acme\"}}'","handlingStrategy":"validation","validationCode":"import json\ntry:\n    parsed = json.loads(plan_str)\nexcept json.JSONDecodeError as exc:\n    raise ValueError(f'plan is not valid JSON: {exc}') from exc","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate with `python3 -m json.tool plan.json` or `jq . plan.json` before running.","Generate plan JSON programmatically rather than hand-editing."],"tags":["cli","json","python","argument-validation","competitors"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}