{"record":{"id":"3090706749795502","repo":"iOfficeAI/OfficeCLI","slug":"one-of-index-after-or-before-is-required-w","errorCode":null,"errorMessage":"One of --index, --after, or --before is required when moving a sheet","messagePattern":"One of --index, --after, or --before is required when moving a sheet","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Add.cs","lineNumber":210,"sourceCode":"\n            Sheet? afterAnchor = null, beforeAnchor = null;\n            if (position?.After != null)\n            {\n                var anchorName = ExtractAnchorSheetName(position.After);\n                afterAnchor = sheets.Elements<Sheet>().FirstOrDefault(s =>\n                    string.Equals(s.Name?.Value, anchorName, StringComparison.OrdinalIgnoreCase))\n                    ?? throw new ArgumentException($\"After anchor not found: {position.After}\");\n            }\n            else if (position?.Before != null)\n            {\n                var anchorName = ExtractAnchorSheetName(position.Before);\n                beforeAnchor = sheets.Elements<Sheet>().FirstOrDefault(s =>\n                    string.Equals(s.Name?.Value, anchorName, StringComparison.OrdinalIgnoreCase))\n                    ?? throw new ArgumentException($\"Before anchor not found: {position.Before}\");\n            }\n            else if (index == null)\n            {\n                throw new ArgumentException(\"One of --index, --after, or --before is required when moving a sheet\");\n            }\n\n            // Self-move guard: moving a sheet after/before itself is a no-op.\n            // Removing first detaches sheetEl, then InsertAfterSelf/InsertBeforeSelf\n            // throws \"parent is null\" and the sheet is lost (data loss).\n            if (ReferenceEquals(afterAnchor, sheetEl) || ReferenceEquals(beforeAnchor, sheetEl))\n                return $\"/{sheetName}\";\n\n            // localSheetId on <definedName> is a 0-based position into\n            // <sheets>; capture the pre-move order so scoped names can be\n            // remapped to the sheets' new positions after the reorder.\n            var preMoveOrder = sheets.Elements<Sheet>().ToList();\n\n            sheetEl.Remove();\n\n            if (afterAnchor != null)\n            {\n                afterAnchor.InsertAfterSelf(sheetEl);","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Add.cs#L192-L228","documentation":"Thrown when moving a whole sheet (sourcePath with no second segment, e.g. \"/Sheet1\") but position is null or carries none of Index/After/Before. Unlike element moves where a null position means 'append', a sheet reorder requires an explicit target because the handler refuses to guess a sheet's new location.","triggerScenarios":"h.Move(\"/Sheet1\", null, null); or Move(\"/Sheet1\", null, new InsertPosition()) with all fields null; passing a position object whose Index is null and After/Before are null.","commonSituations":"Caller assumes whole-sheet Move defaults to append like Add does; refactored code dropped the position argument; CLI invocation omitted --index/--after/--before.","solutions":["Pass InsertPosition.AtIndex(n) for an absolute 1-based slot.","Pass InsertPosition.AfterElement(\"/<sheet>\") or BeforeElement(\"/<sheet>\") for a relative reorder.","If you meant 'move to end', compute the last index from the sheet count and pass AtIndex(count)."],"exampleFix":"// before\nh.Move(\"/Sheet1\", null, null); // no target -> throws\n// after\nh.Move(\"/Sheet1\", null, InsertPosition.AtIndex(0)); // move to first position","handlingStrategy":"validation","validationCode":"// Whole-sheet move (no element segment) requires an explicit target.\nbool isSheetMove = sourcePath.TrimStart('/').Split('/', 2).Length < 2;\nbool hasTarget = pos is { Index: not null } || pos?.After != null || pos?.Before != null;\nif (isSheetMove && !hasTarget)\n    throw new InvalidOperationException(\"Sheet reorder requires --index, --after, or --before\");","typeGuard":"static bool HasMoveTarget(InsertPosition? p) =>\n    p is { Index: not null } || (p?.After != null) || (p?.Before != null);","tryCatchPattern":null,"preventionTips":["Never pass null position for a whole-sheet Move.","Use InsertPosition.AtIndex/AfterElement/BeforeElement factories so a target is always set.","Compute 'move to end' explicitly as AtIndex(sheetCount)."],"tags":["excel","openxml","move","sheet-reorder","missing-argument"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}