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

  1. Load the document first (getDomFromZip or getDomFromXML), then call registerNamespace.
  2. Move registerNamespace calls to after the load step in your setup code.
  3. If reusing a reader, ensure it still holds its DOM (it was not recreated) before registering.
  4. 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

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


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)