{"record":{"id":"4322ba9f63e5a006","repo":"dompdf/dompdf","slug":"parent-table-not-found-for-table-cell-4322ba","errorCode":null,"errorMessage":"Parent table not found for table cell","messagePattern":"Parent table not found for table cell","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/Renderer/TableCell.php","lineNumber":37,"sourceCode":"{\n    /**\n     * @param Frame $frame\n     */\n    function render(Frame $frame)\n    {\n        $style = $frame->get_style();\n        $node = $frame->get_node();\n\n        if (trim($node->nodeValue) === \"\" && $style->empty_cells === \"hide\") {\n            return;\n        }\n\n        $this->_set_opacity($frame->get_opacity($style->opacity));\n\n        $border_box = $frame->get_border_box();\n        $table = Table::find_parent_table($frame);\n        if ($table === null) {\n            throw new Exception(\"Parent table not found for table cell\");\n        }\n\n        if ($table->get_style()->border_collapse !== \"collapse\") {\n            $this->_render_background($frame, $border_box);\n            $this->_render_border($frame, $border_box);\n            $this->_render_outline($frame, $border_box);\n        } else {\n            // The collapsed case is slightly complicated...\n\n            $cells = $table->get_cellmap()->get_spanned_cells($frame);\n\n            if (is_null($cells)) {\n                return;\n            }\n\n            // Render the background to the padding box, as the cells are\n            // rendered individually one after another, and we don't want the\n            // background to overlap an adjacent border","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/dompdf/dompdf/blob/b14267808b811db092f53830f81f4706f4917c79/src/Renderer/TableCell.php#L19-L55","documentation":"This exception is thrown by the TableCell renderer when it cannot find a Table ancestor for the table-cell frame it is asked to render. During layout, dompdf walks the frame tree upward via Table::find_parent_table() (src/FrameDecorator/Table.php:158) looking for a frame where is_table() is true; if the walk reaches the top without finding one, it returns null and TableCell::render() aborts with this message. It almost always indicates a broken frame tree, which in practice means invalid HTML: a td/th element that never ended up inside a proper table structure after parsing/tree-building. This is an internal consistency error, not a user-configurable condition.","triggerScenarios":"Rendering HTML that contains a <td> or <th> not nested inside a <table><tr> chain (e.g. a bare <td> directly under <body> or a <div>); malformed table markup such as a <tr> or <table> closed early so libxml's tree builder reparents the cell outside the table subtree; HTML from WYSIWYG editors or templating that emits fragments like '<td>...</td>' without the surrounding table tags; or custom code that manipulates/injects cell frames into the dompdf FrameTree without a Table parent.","commonSituations":"Server-side PDF generation from user-submitted or CMS-sourced HTML that contains copy-pasted table fragments missing the outer <table> tag; HTML truncated by a max-length column or a regex-based sanitizer that strips the <table> wrapper but leaves <td>; older dompdf versions where certain nested-table and colspan/rowspan combinations (e.g. cells inside nested tables split across pages) could leave orphaned cell frames after table/tree fixups; feeding an HTML fragment rather than a full document to Dompdf::loadHtml() and bypassing normal tree building.","solutions":["Fix the source HTML so every <td>/<th> sits inside a well-formed <table> ... <tr> ... structure, then re-render.","Sanitize/repair the HTML before loadHtml(): parse it with DOMDocument, find td/th nodes with no table ancestor, and either wrap them in a table or drop them.","Upgrade dompdf to the latest release — several historical bugs where valid nested tables produced orphaned cell frames (triggering this exact exception) have been fixed in the table layout code.","If you build or mutate frames yourself, ensure any TableCell frame you insert has a Table frame as an ancestor before rendering.","Wrap the render() call in a try/catch for this case and fall back to an error page or HTML-escaped output so one bad document does not kill a batch job."],"exampleFix":"// before\n$html = '<td>Price</td><td>12.00</td>'; // bare cells, no table wrapper\n$dompdf->loadHtml($html);\n$dompdf->render(); // throws \"Parent table not found for table cell\"\n\n// after\n$html = '<table><tr><td>Price</td><td>12.00</td></tr></table>';\n$dompdf->loadHtml($html);\n$dompdf->render();","handlingStrategy":"validation","validationCode":"// Before loadHtml(): ensure every cell is inside a table\n$doc = new DOMDocument();\nlibxml_use_internal_errors(true);\n$doc->loadHTML($html, LIBXML_NOWARNING | LIBXML_NOERROR);\n$xpath = new DOMXPath($doc);\n$badCells = $xpath->query('//td[not(ancestor::table)] | //th[not(ancestor::table)]');\nif ($badCells->length > 0) {\n    // wrap strays in a table, drop them, or reject the input\n    $html = stripOrWrapStrayCells($doc, $badCells);\n}\n$dompdf->loadHtml($html);","typeGuard":null,"tryCatchPattern":"try {\n    $dompdf->render();\n} catch (\\Exception $e) {\n    if (str_contains($e->getMessage(), 'Parent table not found for table cell')) {\n        // log the offending HTML, sanitize it, or return a safe fallback document\n        logger()->warning('dompdf: stray table cell in input HTML', ['html' => $html]);\n        $dompdf->loadHtml(htmlspecialchars($html));\n        $dompdf->render();\n    } else {\n        throw $e;\n    }\n}","preventionTips":["Always emit tables through a templating layer that guarantees the <table>/<tr> wrapper instead of concatenating raw <td> fragments.","Run user-supplied HTML through an HTML sanitizer/repairer (DOMDocument round-trip, tidy, or htmlpurifier) before passing it to loadHtml().","Keep dompdf up to date — several orphaned-cell frame-tree bugs that trigger this exception were fixed in later releases.","In automated/batch pipelines, wrap render() in a catch-all that records the source HTML so bad documents can be reproduced and fixed."],"tags":["dompdf","html-parsing","table-layout","frame-tree","invalid-html"],"backgroundTag":"malformed-html-table-structure","analyzedSha":"b14267808b811db092f53830f81f4706f4917c79","analyzedAt":"2026-08-21T03:01:11.111Z","schemaVersion":2},"datasetVersion":"2026-08-21T03:17:12.404Z"}