{"record":{"id":"d5d0bf15eba42721","repo":"iOfficeAI/OfficeCLI","slug":"anchor-sheet-asegs-0-must-match-target-sheet","errorCode":null,"errorMessage":"Anchor sheet '{aSegs[0]}' must match target sheet '{sheetName}'","messagePattern":"Anchor sheet '(.+?)' must match target sheet '(.+?)'","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Add.Cells.cs","lineNumber":195,"sourceCode":"\n        // Resolve --before / --after anchors (same shape as Excel CopyFrom):\n        // anchor must be /<sheetName>/row[K] in the same sheet.\n        // CONSISTENCY(zero-based-index): per project convention, position.Index\n        // is 0-based across all formats (--index 0 = head, --index 1 = before\n        // 2nd slot). xlsx Row uses a 1-based RowIndex internally, so +1 here\n        // and let the existing branch keep treating `index` as a 1-based row\n        // number (which is also what the anchor branch below produces).\n        int? index = position?.Index.HasValue == true ? position!.Index!.Value + 1 : (int?)null;\n        if (index == null && position != null && (position.After != null || position.Before != null))\n        {\n            int FindAnchorRow(string anchorPath)\n            {\n                var aSegs = anchorPath.TrimStart('/').Split('/', 2);\n                if (aSegs.Length < 2)\n                    throw new ArgumentException(\n                        $\"Anchor must be a row path like /{sheetName}/row[K], got: {anchorPath}\");\n                if (!aSegs[0].Equals(sheetName, StringComparison.OrdinalIgnoreCase))\n                    throw new ArgumentException(\n                        $\"Anchor sheet '{aSegs[0]}' must match target sheet '{sheetName}'\");\n                var am = Regex.Match(aSegs[1], @\"^row\\[(\\d+)\\]$\");\n                if (!am.Success)\n                    throw new ArgumentException(\n                        $\"Anchor must be a row path like /{sheetName}/row[K], got: {anchorPath}\");\n                return (int)uint.Parse(am.Groups[1].Value);\n            }\n            // For row insertion, --before /Sheet1/row[5] means \"the new row\n            // takes the row[5] slot, original row[5] shifts to row[6]\". So\n            // resolved index == anchor row number. --after /Sheet1/row[5]\n            // means index == anchor + 1.\n            if (position.Before != null) index = FindAnchorRow(position.Before);\n            else index = FindAnchorRow(position.After!) + 1;\n        }\n\n        var rowIdx = index ?? ((int)(sheetData.Elements<Row>().LastOrDefault()?.RowIndex?.Value ?? 0) + 1);\n\n        // Excel's row space tops out at 1048576 (2^20). The append branch","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Add.Cells.cs#L177-L213","documentation":"Thrown by FindAnchorRow when the anchor path's sheet segment does not match the target sheet (case-insensitive comparison). Row insertion anchors must reference the same sheet as the parent path — you cannot insert a row in Sheet1 anchored to a row in Sheet2. The comparison uses StringComparison.OrdinalIgnoreCase so only a genuine different-sheet mismatch triggers this, not a casing difference.","triggerScenarios":"Calling Add with parent path '/Sheet1' and a --before or --after anchor like '/Sheet2/row[5]'. The resolver extracts 'Sheet2' from the anchor and compares it to 'Sheet1' from the parent path; the mismatch is rejected because cross-sheet anchoring is not meaningful for row insertion.","commonSituations":"A copy-paste error where the anchor path was taken from a different sheet's context; a script that hardcodes the anchor sheet name while the parent sheet is parameterized; confusion when the parent path and anchor path are built from different sources.","solutions":["Ensure the anchor path references the same sheet as the parent path: '/<sheetName>/row[K]' where <sheetName> matches the parent.","If you need to reference a row in a different sheet, use a copy/move operation instead of an insertion anchor.","Parameterize both the parent sheet name and the anchor sheet name from the same variable."],"exampleFix":"// before: anchor sheet differs from target sheet\nhandler.Add(\"/Sheet1\", \"row\", null, new { before = \"/Sheet2/row[5]\" }); // mismatch\n\n// after: anchor in the same sheet\nhandler.Add(\"/Sheet1\", \"row\", null, new { before = \"/Sheet1/row[5]\" });","handlingStrategy":"validation","validationCode":"// Validate the anchor references the same sheet as the target\nstatic bool IsSameSheetAnchor(string anchor, string targetSheet)\n{\n    var segs = anchor.TrimStart('/').Split('/', 2);\n    return segs.Length >= 1 && segs[0].Equals(targetSheet, StringComparison.OrdinalIgnoreCase);\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    handler.Add($\"/{sheetName}\", \"row\", new InsertPosition { Before = anchor }, properties);\n}\ncatch (ArgumentException ex) when (ex.Message.Contains(\"must match target sheet\"))\n{\n    // Anchor references a different sheet — fix the anchor or use a different operation\n    logger.LogError(\"Anchor sheet '{AnchorSheet}' must match target '{Target}'.\", anchor, sheetName);\n    throw;\n}","preventionTips":["Ensure the anchor's sheet name matches the parent path's sheet.","Parameterize both the parent sheet and the anchor from the same variable.","For cross-sheet operations, use copy/move instead of insertion anchors.","Avoid copy-pasting anchors from a different sheet's context."],"tags":["excel","add-row","anchor-path","sheet-mismatch","argument-validation"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}