PHPOffice/PHPWord · error · InvalidArgumentException

Invalid text, should be a string or a TextRun

Error message

Invalid text, should be a string or a TextRun

What it means

Title's constructor requires its text to be either a string (converted via SharedText::toUTF8) or a TextRun instance; anything else throws InvalidArgumentException. This ensures heading content is always renderable into the document.

Solutions

  1. Cast the value to a string: new Title((string) $heading, $depth).
  2. Use a TextRun for rich text instead of a plain Text or array of elements.
  3. Guard with is_string($t) || $t instanceof TextRun before constructing.
  4. Catch InvalidArgumentException in code paths where the text source is dynamic.

Example fix

// before
$section->addTitle($numPages);
// after
$section->addTitle((string) $numPages);
Defensive patterns

Strategy: type-guard

Validate before calling

if (!is_string($text) && !$text instanceof \PhpOffice\PhpWord\Element\TextRun) { $text = (string) $text; }

Type guard

function isValidTitleText($text): bool { return is_string($text) || $text instanceof \PhpOffice\PhpWord\Element\TextRun; }

Try / catch

try { $section->addTitle($text, $depth); } catch (\InvalidArgumentException $e) { $section->addTitle((string) $text, $depth); }

Prevention

When it happens

Trigger: new Title(123, 1), new Title(null), new Title(new Text('x')), or new Title(['a']) — any non-string, non-TextRun first argument.

Common situations: Passing numeric heading values without casting, passing Element\Text instead of TextRun, or forwarding unvalidated user input to addTitle().

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of PHPOffice/PHPWord@aef95c0415 (2026-09-14). Data as JSON: /api/errors/28c2b474ebcbcc15. Report an issue: GitHub.

Appendix: source

Thrown at src/PhpWord/Element/Title.php:78

     *
     * @var int
     */
    private $pageNumber;

    /**
     * Create a new Title Element.
     *
     * @param string|TextRun $text
     * @param int $depth
     */
    public function __construct($text, $depth = 1, ?int $pageNumber = null)
    {
        if (is_string($text)) {
            $this->text = SharedText::toUTF8($text);
        } elseif ($text instanceof TextRun) {
            $this->text = $text;
        } else {
            throw new InvalidArgumentException('Invalid text, should be a string or a TextRun');
        }

        $this->depth = $depth;
        $styleName = $depth === 0 ? 'Title' : "Heading_{$this->depth}";
        if (array_key_exists($styleName, Style::getStyles())) {
            $this->style = str_replace('_', '', $styleName);
        }

        if ($pageNumber !== null) {
            $this->pageNumber = $pageNumber;
        }
    }

    /**
     * Get Title Text content.
     *
     * @return string|TextRun
     */

View on GitHub (pinned to aef95c0415)