w7corp/easywechat · error · RuntimeException
Invalid event type.
Error message
Invalid event type.
What it means
Thrown by Pay/Message::getEventType() when the decoded webhook message's original attributes have no string event_type field. WeChat Pay V3 notifications always carry event_type (e.g. TRANSACTION.SUCCESS); getting a non-string means the Message was built from something that is not a V3 event notification.
Source
Thrown at src/Pay/Message.php:34
/**
* @return array<string, mixed>
*/
public function getOriginalAttributes(): array
{
$attributes = json_decode($this->getOriginalContents(), true);
return is_array($attributes) ? $attributes : [];
}
/**
* @throws RuntimeException
*/
public function getEventType(): ?string
{
$eventType = $this->getOriginalAttributes()['event_type'];
if (! is_string($eventType)) {
throw new RuntimeException('Invalid event type.');
}
return $eventType;
}
}
View on GitHub (pinned to f0cf0a8b83)
Solutions
- Branch on request Content-Type and only call getEventType()/handle() for V3 JSON notifications; route V2 XML through handlePaidCallback/decodeXmlMessage flow
- Guard before use: check $message->getOriginalAttributes()['event_type'] exists and is a string
- Log the raw body when it fails to identify what actually arrived
Example fix
// before
$message = $server->getRequestMessage();
$type = $message->getEventType(); // RuntimeException on V2/odd payloads
// after
$attrs = $message->getOriginalAttributes();
$type = isset($attrs['event_type']) && is_string($attrs['event_type'])
? $message->getEventType()
: null;
if ($type === null) { /* not a V3 event notification: route accordingly */ } Defensive patterns
Strategy: type-guard
Validate before calling
$attrs = $message->getOriginalAttributes();
if (! isset($attrs['event_type']) || ! is_string($attrs['event_type'])) {
// not a V3 event notification - skip event routing
return 'success';
} Type guard
function isV3EventNotification(\EasyWeChat\Pay\Message $m): bool
{
$t = $m->getOriginalAttributes()['event_type'] ?? null;
return is_string($t) && $t !== '';
} Try / catch
try {
$type = $message->getEventType();
} catch (\EasyWeChat\Kernel\Exceptions\RuntimeException $e) {
if ($e->getMessage() === 'Invalid event type.') {
// log raw body, ack with success to avoid redelivery storms
return 'success';
}
throw $e;
} Prevention
- Branch webhook handling on Content-Type before touching event_type
- Ack-and-log unknown payloads instead of throwing
- Feed recorded real notifications to tests, not hand-made arrays
When it happens
Trigger: Calling $message->getEventType() (or using Server::handle() routing which matches on event type) on a message whose origin body lacks event_type: V2 XML callbacks parsed into the same Message class, a plain API response payload reused as Message, or a manually constructed Message from test fixtures.
Common situations: Pointing the same handler at both V2 (XML) and V3 (JSON) webhooks; unit tests feeding minimal arrays; calling getRequestMessage() on a verification request instead of a real event; payload mangled by middleware that rewrote the raw body.
Related errors
- Invalid request body.
- V2 secret key is required.
- Failed to decrypt request message.
- Invalid request.
- Invalid request resource.
AI-assisted analysis of w7corp/easywechat@f0cf0a8b83 (2026-08-21).
Data as JSON: /api/errors/2f0b2e3b1fd4d8a8.
Report an issue: GitHub.