w7corp/easywechat · error · InvalidArgumentException
Invalid Response type "%s".
Error message
Invalid Response type "%s".
What it means
XML-mode normalizeResponse() accepts arrays, strings and numerics (strings/numerics become text replies) and throws on everything else, naming gettype in the message. Objects, resources and true from a handler hit this path; null and '' are treated as empty by transformToReply() and answered with the automatic 'success' response, so they never throw.
Source
Thrown at src/Kernel/Traits/RespondXmlMessage.php:78
foreach ($response as $key => $value) {
$normalized[(string) $key] = $value;
}
if (! isset($normalized['MsgType'])) {
throw new InvalidArgumentException('MsgType cannot be empty.');
}
return $normalized;
}
if (is_string($response) || is_numeric($response)) {
return [
'MsgType' => 'text',
'Content' => $response,
];
}
throw new InvalidArgumentException(
sprintf('Invalid Response type "%s".', gettype($response))
);
}
/**
* @param array<string, mixed> $attributes
*
* @throws RuntimeException
*/
protected function createXmlResponse(array $attributes, ?Encryptor $encryptor = null): ResponseInterface
{
$xml = Xml::build($attributes);
return new Response(200, ['Content-Type' => 'application/xml'], $encryptor ? $encryptor->encrypt($xml) : $xml);
}
}
View on GitHub (pinned to f0cf0a8b83)
Solutions
- Return a string, an array, or a PSR ResponseInterface from reply handlers.
- For 'handled, no reply', return null or '' — the SDK replies 'success'.
- Cast or restructure boolean-returning helpers so the reply chain yields a supported type.
Example fix
// before: boolean return
public function __invoke($message, $next) { $this->process($message); return true; }
// after: empty return means the automatic 'success' no-op reply
public function __invoke($message, $next) { $this->process($message); return ''; } Defensive patterns
Strategy: validation
Validate before calling
if (is_object($reply) || is_bool($reply) || is_resource($reply)) { $reply = ''; } Type guard
function isAcceptableXmlReply(mixed $r): bool { return $r === null || $r === '' || is_string($r) || is_numeric($r) || is_array($r) || $r instanceof \Psr\Http\Message\ResponseInterface; } Try / catch
try { return $server->serve(); } catch (\EasyWeChat\Kernel\Exceptions\InvalidArgumentException $e) { if (str_contains($e->getMessage(), 'Invalid Response type')) { \Log::warning('handler returned unsupported reply type'); return new \Nyholm\Psr7\Response(200, [], 'success'); } throw $e; } Prevention
- Document handler contracts as string|array|ResponseInterface|null
- Avoid boolean returns inside reply chains
- Add static analysis annotations for handler return types
When it happens
Trigger: A handler returns true (a 'handled' flag), an object such as the incoming Message instance, a DTO/ArrayObject, or a resource; passthrough handlers doing return $message;.
Common situations: Middleware pipelines whose handlers return booleans; returning Laravel models or value objects from business code; returning the result of a void-ish API that is an object.
Related errors
- MsgType cannot be empty.
- Request ciphertext must not be empty.
- msgtype cannot be empty.
- Invalid Response type "%s".
- token or aes_key cannot be empty.
AI-assisted analysis of w7corp/easywechat@f0cf0a8b83 (2026-08-21).
Data as JSON: /api/errors/440d5b349c410bd2.
Report an issue: GitHub.