{"record":{"id":"450a0fadfaa07d6a","repo":"iOfficeAI/OfficeCLI","slug":"source-range-has-no-data-rows","errorCode":null,"errorMessage":"Source range has no data rows","messagePattern":"Source range has no data rows","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Core/PivotTableHelper.Readback.cs","lineNumber":418,"sourceCode":"\n        // Locate the source worksheet via the workbook part.\n        var workbookPart = pivotPart.GetParentParts().OfType<WorksheetPart>().FirstOrDefault()\n            ?.GetParentParts().OfType<WorkbookPart>().FirstOrDefault()\n            ?? throw new InvalidOperationException(\"Workbook part not reachable from pivot table part\");\n        var sheetEntry = workbookPart.Workbook?.Sheets?.Elements<Sheet>()\n            .FirstOrDefault(s => s.Name?.Value == newSheetName)\n            ?? throw new ArgumentException($\"Source sheet not found: {newSheetName}\");\n        if (sheetEntry.Id?.Value is not string srcRelId)\n            throw new InvalidOperationException(\"Source sheet has no relationship id\");\n        var sourceWsPart = workbookPart.GetPartById(srcRelId) as WorksheetPart\n            ?? throw new InvalidOperationException(\"Source sheet relationship does not resolve to a WorksheetPart\");\n\n        // Re-read source data from the new range.\n        var (headers, columnData, _) = ReadSourceData(sourceWsPart, newRef);\n        if (headers.Length == 0)\n            throw new ArgumentException(\"Source range has no data\");\n        if (columnData.Count == 0 || columnData[0].Length == 0)\n            throw new ArgumentException(\"Source range has no data rows\");\n\n        // R15-2: Before mutating any cache/pivot state, validate that existing\n        // row/col/value/filter field references still fit inside the new\n        // (possibly narrower) header list. A silent drop or index clamp here\n        // would leave the DataFields pointing past the rendered columnData,\n        // crashing RenderPivotIntoSheet with ArgumentOutOfRangeException.\n        // Prefer strict error over data loss: user must explicitly restate the\n        // affected axes in the same Set call if they intended to drop them.\n        var newFieldCount = headers.Length;\n        var existingPivotDef = pivotPart.PivotTableDefinition;\n        if (existingPivotDef != null)\n        {\n            // Axes that the same Set call is explicitly overwriting are\n            // excluded from validation — their new values will be parsed\n            // against the fresh headers by RebuildFieldAreas.\n            bool rowsOverwritten = pendingFieldAreaProps?.ContainsKey(\"rows\") == true;\n            bool colsOverwritten = pendingFieldAreaProps?.ContainsKey(\"cols\") == true;\n            bool valuesOverwritten = pendingFieldAreaProps?.ContainsKey(\"values\") == true;","sourceCodeStart":400,"sourceCodeEnd":436,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/PivotTableHelper.Readback.cs#L400-L436","documentation":"Thrown by RefreshPivotCacheFromSource when headers were found but columnData has zero rows (columnData.Count == 0 or columnData[0].Length == 0). The source range is header-only — e.g. A1:D1 has column names but no data rows beneath them. A pivot with zero source records produces an empty cache; this guard rejects it early with the same ArgumentException family as the no-headers case.","triggerScenarios":"Calling Set source=A1:D1 (only the header row, no data). Or pointing at a range whose data rows are all blank so ReadSourceData yields zero record rows.","commonSituations":"The source range's bottom boundary is set too high (e.g. A1:D1 instead of A1:D100); the worksheet has headers but the data was cleared; template worksheet where data hasn't been populated yet.","solutions":["Extend the range to include at least one data row below the header (e.g. A1:D2 minimum).","Confirm the worksheet actually contains populated data rows in the specified columns.","If using a dynamic range, verify it resolves to more than one row."],"exampleFix":"// before\nSet pivot source=Sheet1!A1:D1\n// after\nSet pivot source=Sheet1!A1:D100","handlingStrategy":"validation","validationCode":"// Before Set source=, confirm the range has at least one data row\nvar (testHeaders, testRows, _) = ReadSourceData(sourceWsPart, testRange);\nif (testHeaders.Length > 0 && (testRows.Count == 0 || testRows[0].Length == 0))\n    throw new ArgumentException($\"Range {testRange} is header-only — no data rows.\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Ensure the range spans at least two rows (header + one data row).","Verify data exists below the header row in the specified columns.","Avoid using single-row ranges as pivot sources."],"tags":["pivot","excel","source-range","empty-data","set-property"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}