{"record":{"id":"9207f956c2c2a396","repo":"iOfficeAI/OfficeCLI","slug":"invalid-json","errorCode":"invalid_json","errorMessage":"Invalid JSON data: parsed to null","messagePattern":"Invalid JSON data: parsed to null","errorType":"error_code","errorClass":"CliException","httpStatus":null,"severity":"error","filePath":"src/officecli/Core/TemplateMerger.cs","lineNumber":53,"sourceCode":"    /// <summary>\n    /// Parse merge data from a string argument. If the value ends with .json and the file exists,\n    /// read from file; otherwise parse as inline JSON.\n    /// </summary>\n    public static Dictionary<string, string> ParseMergeData(string dataArg)\n    {\n        string jsonText;\n\n        if (dataArg.EndsWith(\".json\", StringComparison.OrdinalIgnoreCase) && File.Exists(dataArg))\n        {\n            jsonText = File.ReadAllText(dataArg);\n        }\n        else\n        {\n            jsonText = dataArg;\n        }\n\n        var jsonNode = JsonNode.Parse(jsonText)\n            ?? throw new CliException(\"Invalid JSON data: parsed to null\")\n            {\n                Code = \"invalid_json\",\n                Suggestion = \"Provide valid JSON object, e.g. '{\\\"name\\\":\\\"Alice\\\"}'\"\n            };\n\n        if (jsonNode is not JsonObject jsonObj)\n            throw new CliException(\"JSON data must be an object (not array or primitive)\")\n            {\n                Code = \"invalid_json\",\n                Suggestion = \"Provide a JSON object, e.g. '{\\\"name\\\":\\\"Alice\\\"}'\"\n            };\n\n        var data = new Dictionary<string, string>();\n        // Pass 1: literal top-level keys win. {{a.b}} with data {\"a.b\":\"X\"}\n        // resolves to \"X\" regardless of whether {\"a\":{\"b\":...}} also exists.\n        // CONSISTENCY(merge-literal-key-precedence): mirrors the hyphen-key\n        // contract (R21) — literal lookup is the canonical path; nested\n        // dot-path flattening is a convenience layered on top, not a","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/TemplateMerger.cs#L35-L71","documentation":"Thrown by TemplateMerger.ParseMergeData when JsonNode.Parse returns null. System.Text.Json returns null only for the literal JSON token 'null' (a file containing just 'null', or the argument string 'null'). The merge needs a JSON object to map placeholders, so a null root is unusable and surfaced as code invalid_json.","triggerScenarios":"Passing the data argument as the literal string 'null'; a .json file whose entire content is the four bytes 'null'; an upstream layer that serialized a null reference to the JSON token null.","commonSituations":"A data file that was never populated (serialized null); an agent passing through a null JSON value; passing the word null meaning 'no data'.","solutions":["Provide a JSON object with your placeholder keys, e.g. '{\"name\":\"Alice\"}'.","If the .json file is empty or contains 'null', populate it with an object.","If you intended 'no substitutions', pass an empty object '{}' rather than null."],"exampleFix":"// before\n--data \"null\"            // parsed to null\n// or file data.json contains: null\n// after\n--data '{\"name\":\"Alice\"}'\n// data.json: {\"name\":\"Alice\"}","handlingStrategy":"validation","validationCode":"// Reject the degenerate 'null' token before merging\nvar trimmed = dataArg.Trim();\nif (trimmed == \"null\" || trimmed.Length == 0)\n    throw new InvalidOperationException(\"merge data must be a JSON object, got null/empty\");","typeGuard":null,"tryCatchPattern":"try { data = TemplateMerger.ParseMergeData(dataArg); }\ncatch (CliException ex) when (ex.Code == \"invalid_json\")\n{ /* show suggestion: provide a JSON object like {\"name\":\"Alice\"} */ }","preventionTips":["Always write an object (even '{}') to data files, never a bare null.","Validate JSON shape in the layer that produces the data argument."],"tags":["json","validation","template","merge"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}