{"record":{"id":"4a3f0f3c33d76699","repo":"iOfficeAI/OfficeCLI","slug":"add-command-requires-parent-field-example","errorCode":null,"errorMessage":"'add' command requires 'parent' field. Example: {\"command\": \"add\", \"parent\": \"/slide[1]\", \"type\": \"shape\", \"props\": {\"text\": \"Hello\"}}","messagePattern":"'add' command requires 'parent' field\\. Example: (.+?)\\}","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/CommandBuilder.cs","lineNumber":1055,"sourceCode":"                    }\n                    // Mirror standalone `set`'s allFailed semantics: if every\n                    // requested property was rejected (nothing applied), the\n                    // step is a failure, not a successful no-op. Without\n                    // this, batch swallowed unsupported_property into an inner\n                    // success=true while the same set issued via the\n                    // standalone set command returned success=false exit 2.\n                    // Per-step verdict flips to false; outer batch envelope\n                    // still rides on the existing partial-success rule.\n                    if (applied.Count == 0)\n                        throw new CliException(string.Join(\"\\n\", parts)) { Code = \"unsupported_property\" };\n                }\n                return string.Join(\"\\n\", parts);\n            }\n            case \"add\":\n            {\n                var parentPath = item.Parent ?? item.Path;\n                if (string.IsNullOrEmpty(parentPath))\n                    throw new ArgumentException(\"'add' command requires 'parent' field. Example: {\\\"command\\\": \\\"add\\\", \\\"parent\\\": \\\"/slide[1]\\\", \\\"type\\\": \\\"shape\\\", \\\"props\\\": {\\\"text\\\": \\\"Hello\\\"}}\");\n                if (string.IsNullOrEmpty(item.Type) && string.IsNullOrEmpty(item.From))\n                    throw new ArgumentException(\"'add' command requires 'type' or 'from' field. Example: {\\\"command\\\": \\\"add\\\", \\\"parent\\\": \\\"/\\\", \\\"type\\\": \\\"slide\\\"}\");\n                InsertPosition? pos = null;\n                if (item.Index.HasValue) pos = InsertPosition.AtIndex(item.Index.Value);\n                else if (!string.IsNullOrEmpty(item.After)) pos = InsertPosition.AfterElement(item.After);\n                else if (!string.IsNullOrEmpty(item.Before)) pos = InsertPosition.BeforeElement(item.Before);\n\n                if (!string.IsNullOrEmpty(item.From))\n                {\n                    var resultPath = handler.CopyFrom(item.From, parentPath, pos);\n                    return $\"Copied to {resultPath}\";\n                }\n                else\n                {\n                    var type = item.Type ?? \"\";\n                    // Wrap props in a tracking dict (matches CLI/resident add): a\n                    // key the handler reads is consumed, so UnusedKeys after Add\n                    // is the generic unsupported-prop set across ALL handlers.","sourceCodeStart":1037,"sourceCodeEnd":1073,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/CommandBuilder.cs#L1037-L1073","documentation":"Thrown by ExecuteBatchItem for a batch \"add\" step when both \"parent\" and \"path\" are null/empty (path is used as a fallback for parent). Add needs a parent container to insert into; there is no implicit root. The example in the message shows the expected shape.","triggerScenarios":"{\"command\":\"add\",\"type\":\"slide\"} (no parent); an add step whose parent/path variables were both empty; a templating bug that dropped the parent field.","commonSituations":"Forgotten parent field in a hand-written batch; a parent computed from a null/empty variable; a generator that emitted type but not parent; copy-paste that lost the parent line.","solutions":["Add a parent: {\"command\":\"add\",\"parent\":\"/\",\"type\":\"slide\"}.","Provide \"path\" as the fallback if parent is unset.","Validate every add step has a non-empty parent (or path) before submission.","For top-level adds (e.g. a new slide), use parent \"/\"."],"exampleFix":"// before\n{\"command\":\"add\",\"type\":\"slide\"}\n// after\n{\"command\":\"add\",\"parent\":\"/\",\"type\":\"slide\"}","handlingStrategy":"validation","validationCode":"var parent = item.Parent ?? item.Path;\nif (string.IsNullOrEmpty(parent))\n    throw new ArgumentException(\"'add' requires a non-empty 'parent' (or 'path')\");","typeGuard":"static bool IsValidAddItem(BatchItem i)\n    => !string.IsNullOrEmpty(i.Parent ?? i.Path)\n       && (!string.IsNullOrEmpty(i.Type) || !string.IsNullOrEmpty(i.From));","tryCatchPattern":null,"preventionTips":["Always set parent (or path) on add steps; use \"/\" for top-level.","Validate add items against the schema before submission.","Guard against null/empty parent variables."],"tags":["batch","add","validation","officecli"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}