{"record":{"id":"95fee8ce8247bee5","repo":"affaan-m/ECC","slug":"invalid-json-in-config-path","errorCode":null,"errorMessage":"Invalid JSON in config: {path}","messagePattern":"Invalid JSON in config: (.+?)","errorType":"exception","errorClass":"ConfigError","httpStatus":null,"severity":"error","filePath":"skills/python-patterns/SKILL.md","lineNumber":153,"sourceCode":"def render_all(items: list[Renderable]) -> str:\n    \"\"\"Render all items that implement the Renderable protocol.\"\"\"\n    return \"\\n\".join(item.render() for item in items)\n```\n\n## Error Handling Patterns\n\n### Specific Exception Handling\n\n```python\n# Good: Catch specific exceptions\ndef load_config(path: str) -> Config:\n    try:\n        with open(path) as f:\n            return Config.from_json(f.read())\n    except FileNotFoundError as e:\n        raise ConfigError(f\"Config file not found: {path}\") from e\n    except json.JSONDecodeError as e:\n        raise ConfigError(f\"Invalid JSON in config: {path}\") from e\n\n# Bad: Bare except\ndef load_config(path: str) -> Config:\n    try:\n        with open(path) as f:\n            return Config.from_json(f.read())\n    except:\n        return None  # Silent failure!\n```\n\n### Exception Chaining\n\n```python\ndef process_data(data: str) -> Result:\n    try:\n        parsed = json.loads(data)\n    except json.JSONDecodeError as e:\n        # Chain exceptions to preserve the traceback","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/skills/python-patterns/SKILL.md#L135-L171","documentation":"Raised as a ConfigError when Python's json.JSONDecodeError is caught while parsing a config file with Config.from_json(f.read()). It signals the file was opened successfully but its contents are not valid JSON. The exception is chained (`from e`) so the original decode error traceback is preserved.","triggerScenarios":"Calling load_config(path) where the file at `path` exists but contains malformed JSON (trailing commas, single quotes, unquoted keys, BOM-prefixed bytes, comments, or a file truncated mid-write). Config.from_json() internally calls json.loads() which raises json.JSONDecodeError.","commonSituations":"Hand-edited JSON config files with comments or trailing commas; a config written by another tool that emitted JSON5 or JSONC; a config file partially written and read during a crash; UTF-8 with BOM from a Windows editor.","solutions":["Validate the file with `python -m json.tool config.json` to get the exact line/column of the syntax error.","Check for common JSON-invalid syntax: comments (// or /* */), trailing commas, single-quoted strings, unquoted keys.","Re-encode the file as plain UTF-8 without BOM (e.g. `sed -i '1s/^\\xEF\\xBB\\xBF//' config.json`).","If you must allow comments/relaxed JSON, parse with json5.loads or strip comments before json.loads, but document that the config schema is no longer strict JSON."],"exampleFix":"// before\n{}\n\n# after: validate and report the exact offset\nimport json\ntry:\n    with open(path) as f:\n        return Config.from_json(f.read())\nexcept json.JSONDecodeError as e:\n    raise ConfigError(f\"Invalid JSON in {path} at line {e.lineno} col {e.colno}: {e.msg}\") from e","handlingStrategy":"validation","validationCode":"import json, pathlib\ndef is_valid_json_file(path):\n    p = pathlib.Path(path)\n    if not p.exists():\n        return False, \"file missing\"\n    try:\n        json.loads(p.read_text(encoding=\"utf-8\"))\n        return True, None\n    except json.JSONDecodeError as e:\n        return False, f\"line {e.lineno} col {e.colno}: {e.msg}\"\n\nok, err = is_valid_json_file(path)\nif not ok:\n    raise SystemExit(f\"refusing to load bad config: {err}\")","typeGuard":"def is_json_decodable(s: str) -> bool:\n    try:\n        json.loads(s)\n        return True\n    except (json.JSONDecodeError, TypeError):\n        return False","tryCatchPattern":"try:\n    cfg = load_config(path)\nexcept ConfigError as e:\n    log.error(\"config load failed: %s\", e)\n    raise SystemExit(2)\nexcept FileNotFoundError as e:\n    log.error(\"config file missing: %s\", e)\n    raise SystemExit(2)","preventionTips":["Lint config files in CI with `python -m json.tool`.","Generate configs from code/templates rather than hand-editing JSON.","Keep configs as TOML/YAML with a schema if comments are needed, and validate at startup."],"tags":["python","config","json","validation"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}