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

  1. Confirm the placeholder is inside a table body row (<w:tr>) in document.xml.
  2. Use cloneRow/deleteRow only for table-bound variables; use setValue() for paragraph variables.
  3. Re-open and re-save the table in Word so a plain <w:tbl> opening tag exists before the placeholder.
  4. 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

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


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)