PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Exception
spgrContainer is unexpectedly null
Error message
spgrContainer is unexpectedly null
What it means
DgContainer::getSpgrContainerOrThrow() returns the shape-group container of a sheet's drawing or throws when unset (src/PhpSpreadsheet/Shared/Escher/DgContainer.php:53). It is hit on read at src/PhpSpreadsheet/Reader/Xls/LoadSpreadsheet.php:440 (chained after getDgContainerOrThrow) and on write at src/PhpSpreadsheet/Writer/Xls/Escher.php:283, where the Xls writer counts shapes when saving drawings.
Source
Thrown at src/PhpSpreadsheet/Shared/Escher/DgContainer.php:53
}
public function setLastSpId(int $value): void
{
$this->lastSpId = $value;
}
public function getSpgrContainer(): ?SpgrContainer
{
return $this->spgrContainer;
}
public function getSpgrContainerOrThrow(): SpgrContainer
{
if ($this->spgrContainer !== null) {
return $this->spgrContainer;
}
throw new SpreadsheetException('spgrContainer is unexpectedly null');
}
public function setSpgrContainer(SpgrContainer $spgrContainer): SpgrContainer
{
return $this->spgrContainer = $spgrContainer;
}
}
View on GitHub (pinned to 65b080eef4)
Solutions
- On the read path: re-save the workbook in Excel/LibreOffice or convert to .xlsx to rebuild Escher data
- On the write path: attach complete Drawing objects via $sheet->getDrawingCollection() rather than building Escher containers manually
- Catch around load/save and quarantine the offending file; report it as malformed
- Update PhpSpreadsheet for reader/writer robustness fixes
Defensive patterns
Strategy: try-catch
Validate before calling
// Write path: ensure drawings go through the public API so containers are complete
$drawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing();
$drawing->setPath($imagePath)->setCoordinates('B2');
$sheet->addDrawing($drawing); // builds a valid Spgr structure on save Try / catch
try {
$writer->save($outFile);
} catch (\PhpOffice\PhpSpreadsheet\Exception $e) {
if (str_contains($e->getMessage(), 'spgrContainer')) {
// strip drawings, then save a drawing-free copy
foreach ($sheet->getDrawingCollection() as $d) { /* remove */ }
}
} Prevention
- Never hand-build Escher/DgContainer graphs; use addDrawing()/getDrawingCollection()
- Validate source workbooks' drawings after heavy third-party processing
- Round-trip suspect files through LibreOffice before re-writing as .xls
When it happens
Trigger: Reading an .xls whose Dg container exists but contains no Spgr container (truncated Escher); writing an .xlsx→.xls conversion where the drawing object graph was built without a shape-group container (programmatic drawings assembled incompletely before save).
Common situations: Batch conversions hitting malformed legacy files; code that constructs Drawing objects or manipulates Escher structures directly and saves as .xls; corrupted archives.
Related errors
- dggContainer is unexpectedly null
- dgContainer is unexpectedly null
- bstoreContainer is unexpectedly null
- Unknown codepage: $codePage
- Syntax error: comma expected in function $function, arg #{$n
AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17).
Data as JSON: /api/errors/43eb758d8a1f81c8.
Report an issue: GitHub.