{"record":{"id":"b1767d65a5697d24","repo":"warpdotdev/warp","slug":"invalid-json","errorCode":"invalid_json","errorMessage":"invalid_json","messagePattern":"invalid_json","errorType":"exception","errorClass":"MergeError","httpStatus":null,"severity":"error","filePath":"resources/bundled/skills/tui-migrate-setup/scripts/merge_mcp_config.py","lineNumber":138,"sourceCode":"    flags = os.O_RDONLY\n    if hasattr(os, \"O_NOFOLLOW\"):\n        flags |= os.O_NOFOLLOW\n    try:\n        descriptor = os.open(path, flags)\n        with os.fdopen(descriptor, \"rb\") as file:\n            raw = file.read(MAX_CONFIG_BYTES + 1)\n    except OSError as error:\n        raise MergeError(\"config_unavailable\") from error\n    if len(raw) > MAX_CONFIG_BYTES:\n        raise MergeError(\"config_too_large\")\n    return raw, stat.S_IMODE(metadata.st_mode)\n\n\ndef _decode_document(raw: bytes) -> dict[str, Any]:\n    try:\n        document = json.loads(raw.decode(\"utf-8\"))\n    except (UnicodeError, json.JSONDecodeError) as error:\n        raise MergeError(\"invalid_json\") from error\n    if not isinstance(document, dict):\n        raise MergeError(\"invalid_config_shape\")\n    return document\n\n\ndef _detect_wrapper(document: dict[str, Any]) -> tuple[tuple[str, ...], dict[str, Any]]:\n    matches: list[tuple[tuple[str, ...], dict[str, Any]]] = []\n    for wrapper_path in WRAPPER_PATHS:\n        value = _path_value(document, wrapper_path)\n        if value is not None:\n            if not isinstance(value, dict):\n                raise MergeError(\"invalid_wrapper_shape\")\n            matches.append((wrapper_path, value))\n\n    if len(matches) > 1:\n        raise MergeError(\"ambiguous_wrapper\")\n    if matches:\n        return matches[0]","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/warpdotdev/warp/blob/e72fd7aacbbb2236d9b3be2aad7e7178fe94b4bc/resources/bundled/skills/tui-migrate-setup/scripts/merge_mcp_config.py#L120-L156","documentation":"_decode_document() parses the bytes read from the config as UTF-8 JSON; UnicodeError (non-UTF-8 bytes, e.g. UTF-16 or a BOM) or json.JSONDecodeError (malformed JSON — comments, trailing commas, truncation, bad quotes) raises invalid_json. The tool requires strict JSON: JSONC with // comments fails exactly here.","triggerScenarios":"Config edited by hand with // comments or a trailing comma; file saved as UTF-16 or UTF-8-with-BOM; truncated write after a crash; a TOML/YAML file passed where JSON is expected.","commonSituations":"Users adding comments because their editor permits JSONC; crash-truncated configs; tools that emit JSONC by default; wrong-file mixups in dotfiles.","solutions":["Validate: python -m json.tool FILE — fix the exact line it reports","Remove comments and trailing commas; the config must be strict JSON","Re-save as UTF-8 without BOM if the failure came from decoding rather than syntax"],"exampleFix":"// before\n{\n  \"mcpServers\": {\n    // my favorite server\n    \"fetch\": { \"command\": \"uvx\", \"args\": [\"mcp-server-fetch\",] }\n  }\n}\n\n// after\n{\n  \"mcpServers\": {\n    \"fetch\": { \"command\": \"uvx\", \"args\": [\"mcp-server-fetch\"] }\n  }\n}","handlingStrategy":"validation","validationCode":"import json\nfrom pathlib import Path\n\njson.loads(Path(p).read_bytes().decode('utf-8'))  # strict JSON, no BOM, no comments","typeGuard":"def is_strict_json_object(raw: bytes) -> bool:\n    try:\n        return isinstance(json.loads(raw.decode('utf-8')), dict)\n    except (UnicodeError, json.JSONDecodeError):\n        return False","tryCatchPattern":"if result.returncode != 0 and 'invalid_json' in result.stderr:\n    # python -m json.tool <path> reports the exact line; fix, then re-run the merge\n    ...","preventionTips":["Keep MCP configs strict JSON — no comments, no trailing commas","Save as UTF-8 without BOM","Validate with python -m json.tool after every hand edit"],"tags":["json","encoding","config"],"backgroundTag":null,"analyzedSha":"e72fd7aacbbb2236d9b3be2aad7e7178fe94b4bc","analyzedAt":"2026-08-16T08:27:25.381Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}