PHPOffice/PHPWord · error · PhpOffice\PhpWord\Exception\Exception
Can not find the start position of the table.
Error message
Can not find the start position of the table.
What it means
findTableStart() walks backwards from the placeholder position in the main document XML looking for the opening '<w:tbl>' tag. If no opening table tag exists before the offset it throws, because deleteRow requires the placeholder to sit inside a table. The document structure is not what the caller assumed.
Solutions
- Confirm the placeholder is inside a table body row (<w:tr>) in document.xml.
- Use cloneRow/deleteRow only for table-bound variables; use setValue() for paragraph variables.
- Re-open and re-save the table in Word so a plain <w:tbl> opening tag exists before the placeholder.
- Unzip the docx and verify '<w:tbl>' precedes the placeholder.
Example fix
// before
$processor->deleteRow('ItemRow'); // 'ItemRow' is a paragraph variable, not in a table -> throws
// after
$processor->setValue('ItemRow', 'value'); // paragraph variable handled with setValue Defensive patterns
Strategy: validation
Validate before calling
function isInTable(string $templatePath, string $var): bool {
$zip = new ZipArchive();
$zip->open($templatePath);
$xml = $zip->getFromName('word/document.xml');
$zip->close();
$pos = strpos($xml, '${' . $var . '}');
return $pos !== false && strrpos(substr($xml, 0, $pos), '<w:tbl>') !== false;
} Try / catch
try {
$processor->deleteRow($var);
} catch (\PhpOffice\PhpWord\Exception\Exception $e) {
if (str_contains($e->getMessage(), 'start position of the table')) {
$processor->setValue('${' . $var . '}', ''); // fallback: blank instead of delete
} else { throw $e; }
} Prevention
- Verify each deleteRow target variable sits inside <w:tbl>/<w:tr> in document.xml.
- Use setValue for paragraph-level variables, deleteRow only for table rows.
- Regenerate templates in Word so standard table markup is present.
- Automate a template lint step in CI that validates variable placement.
When it happens
Trigger: deleteRow() called with a placeholder that is not inside a <w:tbl> element — e.g. the variable is in a normal paragraph, in a header/footer rather than the main part, or the surrounding table markup was altered by another tool.
Common situations: Using deleteRow on a variable that lives outside any table; template regenerated by another tool that alters table XML; placeholder placed in headers/footers instead of the document body.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Can not delete row , template variable not found or…
- Can not find the start position of the row to clone.
- The part " " doesn't exist
- Could not load the given XML document.
- Invalid value, on of ' . implode(', ', $position) . '…
AI-assisted analysis of PHPOffice/PHPWord@aef95c0415 (2026-09-14).
Data as JSON: /api/errors/b081e75c58b61543.
Report an issue: GitHub.
Appendix: source
Thrown at src/PhpWord/TemplateProcessor.php:1224
* Find the start position of the nearest table before $offset.
*/
private function findTableStart(int $offset): int
{
$rowStart = strrpos(
$this->tempDocumentMainPart,
'<w:tbl ',
((strlen($this->tempDocumentMainPart) - $offset) * -1)
);
if (!$rowStart) {
$rowStart = strrpos(
$this->tempDocumentMainPart,
'<w:tbl>',
((strlen($this->tempDocumentMainPart) - $offset) * -1)
);
}
if (!$rowStart) {
throw new Exception('Can not find the start position of the table.');
}
return $rowStart;
}
/**
* Find the end position of the nearest table row after $offset.
*/
private function findTableEnd(int $offset): int
{
return strpos($this->tempDocumentMainPart, '</w:tbl>', $offset) + 7;
}
/**
* Find the start position of the nearest table row before $offset.
*
* @param int $offset
*View on GitHub (pinned to aef95c0415)