iOfficeAI/OfficeCLI · critical · InvalidOperationException
Corrupt file: worksheet data missing
Error message
Corrupt file: worksheet data missing
What it means
Thrown by GetSheet when a WorksheetPart's .Worksheet property is null. The part exists in the package but its underlying sheet XML is missing or unreadable — a corrupt OOXML package, not a caller bug. InvalidOperationException (not ArgumentException) signals file-level corruption.
Source
Thrown at src/officecli/Handlers/Excel/ExcelHandler.Helpers.Sheet.cs:189
/// Resolve sheet[N] index references in the first segment of a normalized path.
/// E.g. /sheet[1]/A1 → /Sheet1/A1 (if the first sheet is named "Sheet1").
/// Must be called after NormalizeExcelPath.
/// </summary>
private string ResolveSheetIndexInPath(string path)
{
if (!path.StartsWith('/')) return path;
var trimmed = path[1..]; // remove leading '/'
var slashIdx = trimmed.IndexOf('/');
var firstSegment = slashIdx >= 0 ? trimmed[..slashIdx] : trimmed;
var resolved = ResolveSheetName(firstSegment);
if (resolved == firstSegment) return path;
return slashIdx >= 0 ? $"/{resolved}/{trimmed[(slashIdx + 1)..]}" : $"/{resolved}";
}
// ==================== Private Helpers ====================
private static Worksheet GetSheet(WorksheetPart part) =>
part.Worksheet ?? throw new InvalidOperationException("Corrupt file: worksheet data missing");
/// <summary>
/// Mark a worksheet as dirty. The actual save (with schema-order reorder) is
/// deferred to <see cref="FlushDirtyParts"/> which runs in Dispose().
/// This replaces per-mutation Save() calls — batch operations over many cells
/// previously triggered one disk write per cell (O(n) saves); now they all
/// flush in a single pass at the end.
/// </summary>
private void SaveWorksheet(WorksheetPart part)
{
_dirtyWorksheets.Add(part);
}
/// <summary>
/// Flush all pending worksheet and stylesheet saves. Called from Dispose().
/// Each dirty WorksheetPart is reordered and saved exactly once regardless
/// of how many mutations targeted it.
/// </summary>View on GitHub (pinned to 1ced45e900)
Solutions
- Open the file in Excel and let it repair, then re-save.
- Regenerate the file from the source of truth.
- Inspect xl/worksheets/_rels/*.rels and the target sheetN.xml to find the broken relationship.
Example fix
null
Defensive patterns
Strategy: try-catch
Validate before calling
// Cannot meaningfully pre-validate; treat the document as untrusted at load time
static bool TryGetWorksheet(WorksheetPart part, out Worksheet ws)
{
ws = part?.Worksheet;
return ws != null;
} Type guard
null
Try / catch
try { /* any cell/range/table op */ }
catch (InvalidOperationException ex) when (ex.Message == "Corrupt file: worksheet data missing")
{ // mark file as corrupt, do not retry on same file; offer repair/regenerate path } Prevention
- Validate generated files by reopening them before publishing.
- Keep source data so a corrupt file can be regenerated.
- Catch InvalidOperationException separately from ArgumentException — it signals corruption, not bad input.
When it happens
Trigger: Opening any .xlsx where xl/worksheets/sheetN.xml is empty, malformed, or removed but the relationship still points at it. Reading any cell/range/table on that sheet triggers GetSheet.
Common situations: Files from a buggy generator that wrote the rels but not the sheet XML; zip-level corruption after a partial write; manual package edits that deleted a sheet part.
Related errors
- Source sheet relationship does not resolve to a WorksheetPar
- Workbook not found
- Table {tableIndex} has no definition
- Corrupt file: workbook missing
- Invalid color value: '{value}'. Expected 6-digit hex RGB (e.
AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13).
Data as JSON: /api/errors/2e2a0d39614aa023.
Report an issue: GitHub.