{"record":{"id":"66492d28b67191c5","repo":"cakephp/cakephp","slug":"invalid-message-type-s-valid-types-are-text-html","errorCode":null,"errorMessage":"Invalid message type: `%s`. Valid types are: `text`, `html`.","messagePattern":"Invalid message type: `(.+?)`\\. Valid types are: `text`, `html`\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Mailer/Message.php","lineNumber":1540,"sourceCode":"        if (isset($config['headers'])) {\n            $this->setHeaders($config['headers']);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Set message body.\n     *\n     * @param array<string, string> $content Content array with keys \"text\" and/or \"html\" with\n     *   content string of respective type.\n     * @return $this\n     */\n    public function setBody(array $content)\n    {\n        foreach ($content as $type => $text) {\n            if (!in_array($type, $this->emailFormatAvailable, true)) {\n                throw new InvalidArgumentException(sprintf(\n                    'Invalid message type: `%s`. Valid types are: `text`, `html`.',\n                    $type,\n                ));\n            }\n\n            $text = str_replace([\"\\r\\n\", \"\\r\"], \"\\n\", $text);\n            $text = $this->encodeString($text, $this->getCharset());\n            $text = $this->wrap($text);\n            $text = implode(\"\\n\", $text);\n            $text = rtrim($text, \"\\n\");\n\n            $property = \"{$type}Message\";\n            $this->$property = $text;\n        }\n\n        $this->boundary = null;\n        $this->message = [];\n","sourceCodeStart":1522,"sourceCodeEnd":1558,"githubUrl":"https://github.com/cakephp/cakephp/blob/1128eba9b09f1946df684811350e26f2cef68fac/src/Mailer/Message.php#L1522-L1558","documentation":"Message::setBody(array $content) iterates over keys of the content array and requires each key to be a valid format in ['text','html']. An unknown key throws InvalidArgumentException('Invalid message type: `%s`. Valid types are: `text`, `html`.').","triggerScenarios":"setBody(['both' => $text]), setBody(['Html' => $html]) (capitalized key), or any key other than 'text'/'html'. Reached via setBodyText/setBodyHtml wrappers only for valid keys, so direct setBody calls are the source.","commonSituations":"Porting CakePHP 3 code that used ['both' => ...]; building the array dynamically from config; using 'plain' or 'raw' as key names.","solutions":["Use only 'text' and 'html' keys in the content array","Replace legacy 'both' with two entries: ['text' => ..., 'html' => ...]","Fix key casing — keys are lowercase and strict (in_array with true)"],"exampleFix":"// before\n$message->setBody(['both' => $content]);\n// after\n$message->setBody(['text' => $content, 'html' => $htmlContent]);","handlingStrategy":"validation","validationCode":"$valid = ['text', 'html'];\nforeach (array_keys($content) as $type) {\n    if (!in_array($type, $valid, true)) {\n        unset($content[$type]); // or throw\n    }\n}\n$message->setBody($content);","typeGuard":"function isValidBodyKey(mixed $type): bool {\n    return is_string($type) && in_array($type, ['text', 'html'], true);\n}","tryCatchPattern":"try {\n    $message->setBody($content);\n} catch (\\InvalidArgumentException $e) {\n    $message->setBody(array_intersect_key($content, ['text' => 1, 'html' => 1]));\n}","preventionTips":["Use setBodyText()/setBodyHtml() wrappers instead of raw setBody","Lowercase all keys before passing","Replace legacy 'both'/'css' keys during upgrades"],"tags":["cakephp","email","validation","argument-error"],"backgroundTag":"invalid-enum-value","analyzedSha":"1128eba9b09f1946df684811350e26f2cef68fac","analyzedAt":"2026-09-12T12:07:00.388Z","contentChangedAt":"2026-09-12T12:07:00.388Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}