{"record":{"id":"43eb758d8a1f81c8","repo":"PHPOffice/PhpSpreadsheet","slug":"spgrcontainer-is-unexpectedly-null","errorCode":null,"errorMessage":"spgrContainer is unexpectedly null","messagePattern":"spgrContainer is unexpectedly null","errorType":"exception","errorClass":"PhpOffice\\PhpSpreadsheet\\Exception","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Shared/Escher/DgContainer.php","lineNumber":53,"sourceCode":"    }\n\n    public function setLastSpId(int $value): void\n    {\n        $this->lastSpId = $value;\n    }\n\n    public function getSpgrContainer(): ?SpgrContainer\n    {\n        return $this->spgrContainer;\n    }\n\n    public function getSpgrContainerOrThrow(): SpgrContainer\n    {\n        if ($this->spgrContainer !== null) {\n            return $this->spgrContainer;\n        }\n\n        throw new SpreadsheetException('spgrContainer is unexpectedly null');\n    }\n\n    public function setSpgrContainer(SpgrContainer $spgrContainer): SpgrContainer\n    {\n        return $this->spgrContainer = $spgrContainer;\n    }\n}\n","sourceCodeStart":35,"sourceCodeEnd":61,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Shared/Escher/DgContainer.php#L35-L61","documentation":"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.","triggerScenarios":"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).","commonSituations":"Batch conversions hitting malformed legacy files; code that constructs Drawing objects or manipulates Escher structures directly and saves as .xls; corrupted archives.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Write path: ensure drawings go through the public API so containers are complete\n$drawing = new \\PhpOffice\\PhpSpreadsheet\\Worksheet\\Drawing();\n$drawing->setPath($imagePath)->setCoordinates('B2');\n$sheet->addDrawing($drawing); // builds a valid Spgr structure on save","typeGuard":null,"tryCatchPattern":"try {\n    $writer->save($outFile);\n} catch (\\PhpOffice\\PhpSpreadsheet\\Exception $e) {\n    if (str_contains($e->getMessage(), 'spgrContainer')) {\n        // strip drawings, then save a drawing-free copy\n        foreach ($sheet->getDrawingCollection() as $d) { /* remove */ }\n    }\n}","preventionTips":["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"],"tags":["xls","escher","drawings","writer","corrupt-file"],"backgroundTag":"unexpected-null-property","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}