w7corp/easywechat · error · BadRequestException
Encrypted message is required, plaintext message rejected.
Error message
Encrypted message is required, plaintext message rejected.
What it means
Server::serve() rejects an inbound callback when the Server was constructed with requireEncryption=true but the request carries no ciphertext (no encrypt_type=aes marker). It is a deliberate security control: plaintext mode drops encryption protection, so with the flag set EasyWeChat throws BadRequestException instead of processing. Per the class docblock, both secure and compatible mode push encrypt_type=aes — only plaintext mode has neither.
Source
Thrown at src/OfficialAccount/Server.php:58
* @throws InvalidConfigException
*/
public function serve(): ResponseInterface
{
$query = $this->getRequest()->getQueryParams();
if ($str = $this->getQueryValue($query, 'echostr')) {
$this->validatePlainRequest($query);
return new Response(200, [], $str);
}
$message = $this->getRequestMessage($this->getRequest());
if ($this->encryptor && $this->isEncryptedRequest($query, $message)) {
$this->prepend($this->decryptRequestMessage($query));
} else {
if ($this->requireEncryption) {
throw new BadRequestException('Encrypted message is required, plaintext message rejected.');
}
$this->validatePlainRequest($query);
}
$response = $this->handle(new Response(200, [], 'success'), $message);
if (! ($response instanceof ResponseInterface)) {
$response = $this->transformToReply($response, $message, $this->encryptor);
}
return ServerResponse::make($response);
}
/**
* @throws Throwable
*/
public function addMessageListener(string $type, callable|string $handler): staticView on GitHub (pinned to f0cf0a8b83)
Solutions
- Switch the official account to 安全模式 (or compatible mode) in the MP console so pushes carry encrypt_type=aes and the Encrypt node
- Or stop requiring encryption: construct the Server without requireEncryption and keep plain signature validation
- For local tests, POST a real encrypted envelope (Encrypt node plus encrypt_type=aes&msg_signature query) instead of raw XML
Example fix
// before: strict server + WeChat account still in plaintext mode $server = new \EasyWeChat\OfficialAccount\Server($request, $app->getEncryptor(), $token, requireEncryption: true); $response = $server->serve(); // BadRequestException // after (option A): switch the console to 安全模式 so pushes are encrypted and keep the strict server // after (option B): keep the console in plaintext and drop the flag $server = new \EasyWeChat\OfficialAccount\Server($request, $app->getEncryptor(), $token); $response = $server->serve();
Defensive patterns
Strategy: validation
Validate before calling
$query = $request->getQueryParams();
$encrypted = strtolower((string) ($query['encrypt_type'] ?? '')) === 'aes';
if (! $encrypted) {
return new \Nyholm\Psr7\Response(400, [], 'encrypted payloads only');
} Try / catch
try {
return $app->getServer()->serve();
} catch (\EasyWeChat\Kernel\Exceptions\BadRequestException $e) {
// plaintext rejected on purpose: log a security event, return 400
return new \Nyholm\Psr7\Response(400, [], 'bad request');
} Prevention
- Keep the MP console message mode and the requireEncryption flag in sync via a documented checklist
- Monitor rejects: a sudden wave of plaintext pushes usually means console settings changed
- Simulate encrypted envelopes (encrypt_type=aes + msg_signature + Encrypt node) in webhook tests
When it happens
Trigger: MP console 消息加解密 set to 明文模式 (plaintext) while the Server requires encryption; replaying or hand-crafting a POST to the callback URL without encrypt_type=aes and the Encrypt node; test harnesses posting raw XML.
Common situations: Team enables strict encryption in code but never switches the mode in the MP console (or vice versa); different accounts per environment where one is plaintext; curl-based webhook testing against a strict server.
Related errors
- token or aes_key cannot be empty.
- The token is required to validate the request signature, ple
- -40001
- No secret configured.
- Failed to get stable access_token: %s
AI-assisted analysis of w7corp/easywechat@f0cf0a8b83 (2026-08-21).
Data as JSON: /api/errors/82adcdaec9517e22.
Report an issue: GitHub.