{"record":{"id":"7f3b7eb4bd2bf3ae","repo":"iOfficeAI/OfficeCLI","slug":"swap-command-requires-path-and-path2-or-to","errorCode":null,"errorMessage":"'swap' command requires 'path' and 'path2' (or 'to') fields. Example: {\"command\": \"swap\", \"path\": \"/slide[1]\", \"path2\": \"/slide[2]\"}","messagePattern":"'swap' command requires 'path' and 'path2' \\(or 'to'\\) fields\\. Example: (.+?)","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/CommandBuilder.cs","lineNumber":1170,"sourceCode":"                InsertPosition? movePos = null;\n                if (item.Index.HasValue) movePos = InsertPosition.AtIndex(item.Index.Value);\n                else if (!string.IsNullOrEmpty(item.After)) movePos = InsertPosition.AfterElement(item.After);\n                else if (!string.IsNullOrEmpty(item.Before)) movePos = InsertPosition.BeforeElement(item.Before);\n                // Pass props to the 4-arg Move like the CLI and resident do; the\n                // batch/MCP path previously dropped move-time properties.\n                var resultPath = handler.Move(path, item.To, movePos, props.Count > 0 ? props : null);\n                return $\"Moved to {resultPath}\";\n            }\n            case \"swap\":\n            {\n                // Second element: accept `path2` (canonical — the single-command\n                // MCP tool and the CLI `swap path1 path2` both use it) or the\n                // legacy `to`. Before path2 was carried, an agent that learned\n                // swap from the single command produced a batch item that\n                // silently failed the path-presence check below.\n                var swapTo = !string.IsNullOrEmpty(item.Path2) ? item.Path2 : item.To;\n                if (string.IsNullOrEmpty(item.Path) || string.IsNullOrEmpty(swapTo))\n                    throw new ArgumentException(\"'swap' command requires 'path' and 'path2' (or 'to') fields. Example: {\\\"command\\\": \\\"swap\\\", \\\"path\\\": \\\"/slide[1]\\\", \\\"path2\\\": \\\"/slide[2]\\\"}\");\n                var (p1, p2) = handler switch\n                {\n                    OfficeCli.Handlers.PowerPointHandler ppt => ppt.Swap(item.Path, swapTo),\n                    OfficeCli.Handlers.WordHandler word => word.Swap(item.Path, swapTo),\n                    OfficeCli.Handlers.ExcelHandler excel => excel.Swap(item.Path, swapTo),\n                    _ => throw new InvalidOperationException(\"swap not supported for this document type\")\n                };\n                return $\"Swapped {p1} <-> {p2}\";\n            }\n            case \"view\":\n            {\n                var mode = item.Mode ?? \"text\";\n                if (mode.ToLowerInvariant() is \"html\" or \"h\")\n                {\n                    if (handler is OfficeCli.Handlers.PowerPointHandler pptH)\n                        return pptH.ViewAsHtml();\n                    if (handler is OfficeCli.Handlers.ExcelHandler excelH)\n                        return excelH.ViewAsHtml();","sourceCodeStart":1152,"sourceCodeEnd":1188,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/CommandBuilder.cs#L1152-L1188","documentation":"Thrown by the batch 'swap' command when item.Path is empty OR the second element (path2, falling back to legacy 'to') is empty. Swap is inherently a two-element operation; either side missing makes it meaningless. The code accepts both the canonical 'path2' key and the older 'to' key to tolerate agents that learned swap from the single-command MCP tool.","triggerScenarios":"A swap item missing 'path', or missing both 'path2' and 'to'. Also when the second element is supplied under a different key like 'parent' or 'target'.","commonSituations":"An agent emits {\"command\":\"swap\",\"path\":\"/slide[1]\"} forgetting the second slide. A caller uses 'to' for move but 'with' for swap, neither recognized.","solutions":["Provide both 'path' and 'path2' (preferred) pointing at sibling elements of the same type.","If you have a legacy caller using 'to', that is still accepted — set item.to to the second path.","Confirm both paths are siblings (e.g. two /slide[N] entries) since Swap expects same-type siblings."],"exampleFix":"// before\n{\"command\":\"swap\",\"path\":\"/slide[1]\"}\n// after\n{\"command\":\"swap\",\"path\":\"/slide[1]\",\"path2\":\"/slide[2]\"}","handlingStrategy":"validation","validationCode":"var swapTo = !string.IsNullOrEmpty(item.Path2) ? item.Path2 : item.To;\nif (string.IsNullOrEmpty(item.Path) || string.IsNullOrEmpty(swapTo))\n    throw new ArgumentException(\"swap needs both 'path' and 'path2' (or 'to')\");","typeGuard":"static bool HasSwapPair(BatchItem i) =>\n    !string.IsNullOrEmpty(i.Path) &&\n    (!string.IsNullOrEmpty(i.Path2) || !string.IsNullOrEmpty(i.To));","tryCatchPattern":"try { result = Dispatch(item); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"'swap' command requires\"))\n{ /* prompt caller for the second path */ }","preventionTips":["Standardize on the canonical 'path2' key for the second element.","Validate both sides are present and are same-type siblings before dispatch.","Prefer 'path2' over the legacy 'to' to avoid confusion with move."],"tags":["batch","swap","missing-field","path"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}