PHPOffice/PHPWord · error · InvalidArgumentException
Dom needs to be loaded before registering a namespace
Error message
Dom needs to be loaded before registering a namespace
What it means
XMLReader wraps a DOMDocument and an optional DOMXpath. registerNamespace() requires that a document has already been loaded (via getDomFromZip/getDomFromXML), because the namespace is registered on the xpath object built from that DOM. If $this->dom is still null, InvalidArgumentException is thrown to prevent calling registerNamespace on nothing.
Solutions
- Load the document first (getDomFromZip or getDomFromXML), then call registerNamespace.
- Move registerNamespace calls to after the load step in your setup code.
- If reusing a reader, ensure it still holds its DOM (it was not recreated) before registering.
- Note: for default/unknown namespaces you may instead use registerXPathNamespace on evaluated nodes.
Example fix
// before
$reader = new XMLReader();
$reader->registerNamespace('w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main');
// after
$reader = new XMLReader();
$reader->getDomFromZip('doc.docx', 'word/document.xml');
$reader->registerNamespace('w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); Defensive patterns
Strategy: type-guard
Validate before calling
$doc = new \ReflectionProperty($reader, 'dom');
$doc->setAccessible(true);
if ($doc->getValue($reader) === null) {
throw new LogicException('Call getDomFromZip/getDomFromXML before registerNamespace');
} Try / catch
try {
$reader->registerNamespace($prefix, $uri);
} catch (\InvalidArgumentException $e) {
if (str_contains($e->getMessage(), 'Dom needs to be loaded')) {
$reader->getDomFromZip($zipFile, $xmlFile);
$reader->registerNamespace($prefix, $uri);
} else {
throw $e;
}
} Prevention
- Enforce load-then-query ordering in a wrapper class or factory method
- Never configure namespaces in a constructor before loading the document
- Reuse the same reader instance without recreating it mid-flow
When it happens
Trigger: Calling registerNamespace($prefix,$uri) on a fresh XMLReader instance before any read/getDomFromZip/getDomFromXML call has populated $this->dom.
Common situations: Setting up namespace prefixes in constructor/initialization code before loading the document; reusing a reader object across requests after state reset; misunderstanding the required load-then-register order.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Invalid value, on of ' . implode(', ', $position) . '…
- Invalid value, on of ' . implode(', ', $restartNumbers) . '…
- Invalid value, dirty or clean possible
- Invalid value, alignments of ' . implode(', '…
- Cannot add in .
AI-assisted analysis of PHPOffice/PHPWord@aef95c0415 (2026-09-14).
Data as JSON: /api/errors/039ffd95f9cd567a.
Report an issue: GitHub.
Appendix: source
Thrown at src/PhpWord/Shared/XMLReader.php:137
}
$result = @$this->xpath->query($path, $contextNode);
return empty($result) ? new DOMNodeList() : $result; // @phpstan-ignore-line
}
/**
* Registers the namespace with the DOMXPath object.
*
* @param string $prefix The prefix
* @param string $namespaceURI The URI of the namespace
*
* @return bool true on success or false on failure
*/
public function registerNamespace($prefix, $namespaceURI)
{
if ($this->dom === null) {
throw new InvalidArgumentException('Dom needs to be loaded before registering a namespace');
}
if ($this->xpath === null) {
$this->xpath = new DOMXpath($this->dom);
}
return $this->xpath->registerNamespace($prefix, $namespaceURI);
}
/**
* Get element.
*
* @param string $path
*
* @return null|DOMElement
*/
public function getElement($path, ?DOMElement $contextNode = null)
{
$elements = $this->getElements($path, $contextNode);View on GitHub (pinned to aef95c0415)