{"record":{"id":"8d69d71184ab776d","repo":"iOfficeAI/OfficeCLI","slug":"add-command-requires-type-or-from-field-exa","errorCode":null,"errorMessage":"'add' command requires 'type' or 'from' field. Example: {\"command\": \"add\", \"parent\": \"/\", \"type\": \"slide\"}","messagePattern":"'add' command requires 'type' or 'from' field\\. Example: (.+?)","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/CommandBuilder.cs","lineNumber":1057,"sourceCode":"                    // 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.\n                    // Previously batch/MCP add saw only Word's curated\n                    // LastAddUnsupportedProps, silently dropping an unknown prop","sourceCodeStart":1039,"sourceCodeEnd":1075,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/CommandBuilder.cs#L1039-L1075","documentation":"Thrown by ExecuteBatchItem for a batch \"add\" step that has a parent but neither \"type\" (what kind of element to create) nor \"from\" (a source path to copy via handler.CopyFrom). At least one of the two is required.","triggerScenarios":"{\"command\":\"add\",\"parent\":\"/slide[1]\"}; an add step where a conditional left both type and from null; type emitted as an empty string.","commonSituations":"Forgotten type field; conditional logic that failed to set a type; a generator that emitted parent but not type; confusion between create (type) and copy (from).","solutions":["Add a type: {\"command\":\"add\",\"parent\":\"/\",\"type\":\"slide\"}.","Or add a from to copy an existing element: {\"command\":\"add\",\"parent\":\"/\",\"from\":\"/slide[1]\"}.","Validate every add step has a non-empty type or from before submission.","Ensure type is not an empty string (empty string fails the IsNullOrEmpty check)."],"exampleFix":"// before\n{\"command\":\"add\",\"parent\":\"/\",\"type\":\"\"}\n// after\n{\"command\":\"add\",\"parent\":\"/\",\"type\":\"slide\"}","handlingStrategy":"validation","validationCode":"if (string.IsNullOrEmpty(item.Type) && string.IsNullOrEmpty(item.From))\n    throw new ArgumentException(\"'add' requires a non-empty 'type' or 'from'\");","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":["Ensure type is non-empty (empty string fails the guard too).","Use 'from' when copying an existing element instead of 'type'.","Validate add items against the schema before submission."],"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"}