PHPOffice/PHPWord · error · PhpOffice\PhpWord\Exception\Exception

Can not find the start position of the row to clone.

Error message

Can not find the start position of the row to clone.

What it means

findRowStart() searches backwards from the placeholder offset for the opening row tag '<w:tr ' or '<w:tr>'. If neither is found it throws. cloneRow()/deleteRow() need the full row element boundaries to duplicate/remove it, so a missing row start means the placeholder is not in a table row.

Solutions

  1. Ensure the placeholder is the content of a cell inside a normal <w:tr> row.
  2. Add a dedicated template row containing just the variable for cloning.
  3. Validate by unzipping the docx and checking document.xml for '<w:tr' before the variable.
  4. Fall back to setValue or manual XML manipulation if the row structure is nonstandard.

Example fix

// before
$processor->cloneRow('headerVar', 3); // headerVar sits in the table header -> throws
// after
$processor->cloneRow('rowVar', 3); // rowVar is inside a body row <w:tr><w:tc><w:t>rowVar</w:t>...
Defensive patterns

Strategy: validation

Validate before calling

function rowVariableExists(string $templatePath, string $var): bool {
    $zip = new ZipArchive();
    $zip->open($templatePath);
    $xml = $zip->getFromName('word/document.xml');
    $zip->close();
    $pos = strpos($xml, '${' . $var . '}');
    if ($pos === false) return false;
    $before = substr($xml, 0, $pos);
    return strrpos($before, '<w:tr ') !== false || strrpos($before, '<w:tr>') !== false;
}

Try / catch

try {
    $processor->cloneRow($var, $count);
} catch (\PhpOffice\PhpWord\Exception\Exception $e) {
    if (str_contains($e->getMessage(), 'start position of the row')) {
        error_log("Variable $var is not inside a table row");
    } else { throw $e; }
}

Prevention

When it happens

Trigger: cloneRow() or deleteRow() called with a variable that is not inside a <w:tr> element — e.g. it sits in the table header/caption, outside any table, or the row markup was removed by hand-editing the template.

Common situations: Variable placed in a table caption or header rather than a body row; cloneRow used on a body-level variable; hand-edited template XML where row markup was removed.

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/05e501866b1948ad. Report an issue: GitHub.

Appendix: source

Thrown at src/PhpWord/TemplateProcessor.php:1253

        return strpos($this->tempDocumentMainPart, '</w:tbl>', $offset) + 7;
    }

    /**
     * Find the start position of the nearest table row before $offset.
     *
     * @param int $offset
     *
     * @return int
     */
    protected function findRowStart($offset)
    {
        $rowStart = strrpos($this->tempDocumentMainPart, '<w:tr ', ((strlen($this->tempDocumentMainPart) - $offset) * -1));

        if (!$rowStart) {
            $rowStart = strrpos($this->tempDocumentMainPart, '<w:tr>', ((strlen($this->tempDocumentMainPart) - $offset) * -1));
        }
        if (!$rowStart) {
            throw new Exception('Can not find the start position of the row to clone.');
        }

        return $rowStart;
    }

    /**
     * Find the end position of the nearest table row after $offset.
     *
     * @param int $offset
     *
     * @return int
     */
    protected function findRowEnd($offset)
    {
        return strpos($this->tempDocumentMainPart, '</w:tr>', $offset) + 7;
    }

    /**

View on GitHub (pinned to aef95c0415)