{"record":{"id":"28c2b474ebcbcc15","repo":"PHPOffice/PHPWord","slug":"invalid-text-should-be-a-string-or-a-textrun","errorCode":null,"errorMessage":"Invalid text, should be a string or a TextRun","messagePattern":"Invalid text, should be a string or a TextRun","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/PhpWord/Element/Title.php","lineNumber":78,"sourceCode":"     *\n     * @var int\n     */\n    private $pageNumber;\n\n    /**\n     * Create a new Title Element.\n     *\n     * @param string|TextRun $text\n     * @param int $depth\n     */\n    public function __construct($text, $depth = 1, ?int $pageNumber = null)\n    {\n        if (is_string($text)) {\n            $this->text = SharedText::toUTF8($text);\n        } elseif ($text instanceof TextRun) {\n            $this->text = $text;\n        } else {\n            throw new InvalidArgumentException('Invalid text, should be a string or a TextRun');\n        }\n\n        $this->depth = $depth;\n        $styleName = $depth === 0 ? 'Title' : \"Heading_{$this->depth}\";\n        if (array_key_exists($styleName, Style::getStyles())) {\n            $this->style = str_replace('_', '', $styleName);\n        }\n\n        if ($pageNumber !== null) {\n            $this->pageNumber = $pageNumber;\n        }\n    }\n\n    /**\n     * Get Title Text content.\n     *\n     * @return string|TextRun\n     */","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/PHPOffice/PHPWord/blob/aef95c04151b5633cc505f672ddd6a71da900ee1/src/PhpWord/Element/Title.php#L60-L96","documentation":"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.","triggerScenarios":"new Title(123, 1), new Title(null), new Title(new Text('x')), or new Title(['a']) — any non-string, non-TextRun first argument.","commonSituations":"Passing numeric heading values without casting, passing Element\\Text instead of TextRun, or forwarding unvalidated user input to addTitle().","solutions":["Cast the value to a string: new Title((string) $heading, $depth).","Use a TextRun for rich text instead of a plain Text or array of elements.","Guard with is_string($t) || $t instanceof TextRun before constructing.","Catch InvalidArgumentException in code paths where the text source is dynamic."],"exampleFix":"// before\n$section->addTitle($numPages);\n// after\n$section->addTitle((string) $numPages);","handlingStrategy":"type-guard","validationCode":"if (!is_string($text) && !$text instanceof \\PhpOffice\\PhpWord\\Element\\TextRun) { $text = (string) $text; }","typeGuard":"function isValidTitleText($text): bool { return is_string($text) || $text instanceof \\PhpOffice\\PhpWord\\Element\\TextRun; }","tryCatchPattern":"try { $section->addTitle($text, $depth); } catch (\\InvalidArgumentException $e) { $section->addTitle((string) $text, $depth); }","preventionTips":["Cast numbers/objects to string before creating titles","Use TextRun for rich heading text, not Text or arrays","Sanitize user-supplied heading content early"],"tags":["phpword","title","type-mismatch","invalid-argument"],"backgroundTag":"invalid-argument-value","analyzedSha":"aef95c04151b5633cc505f672ddd6a71da900ee1","analyzedAt":"2026-09-14T10:53:58.933Z","contentChangedAt":"2026-09-14T10:53:58.933Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}