{"record":{"id":"2f0b2e3b1fd4d8a8","repo":"w7corp/easywechat","slug":"invalid-event-type","errorCode":null,"errorMessage":"Invalid event type.","messagePattern":"Invalid event type\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/Pay/Message.php","lineNumber":34,"sourceCode":"    /**\n     * @return array<string, mixed>\n     */\n    public function getOriginalAttributes(): array\n    {\n        $attributes = json_decode($this->getOriginalContents(), true);\n\n        return is_array($attributes) ? $attributes : [];\n    }\n\n    /**\n     * @throws RuntimeException\n     */\n    public function getEventType(): ?string\n    {\n        $eventType = $this->getOriginalAttributes()['event_type'];\n\n        if (! is_string($eventType)) {\n            throw new RuntimeException('Invalid event type.');\n        }\n\n        return $eventType;\n    }\n}\n","sourceCodeStart":16,"sourceCodeEnd":40,"githubUrl":"https://github.com/w7corp/easywechat/blob/f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8/src/Pay/Message.php#L16-L40","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n$message = $server->getRequestMessage();\n$type = $message->getEventType(); // RuntimeException on V2/odd payloads\n// after\n$attrs = $message->getOriginalAttributes();\n$type = isset($attrs['event_type']) && is_string($attrs['event_type'])\n    ? $message->getEventType()\n    : null;\nif ($type === null) { /* not a V3 event notification: route accordingly */ }","handlingStrategy":"type-guard","validationCode":"$attrs = $message->getOriginalAttributes();\nif (! isset($attrs['event_type']) || ! is_string($attrs['event_type'])) {\n    // not a V3 event notification - skip event routing\n    return 'success';\n}","typeGuard":"function isV3EventNotification(\\EasyWeChat\\Pay\\Message $m): bool\n{\n    $t = $m->getOriginalAttributes()['event_type'] ?? null;\n    return is_string($t) && $t !== '';\n}","tryCatchPattern":"try {\n    $type = $message->getEventType();\n} catch (\\EasyWeChat\\Kernel\\Exceptions\\RuntimeException $e) {\n    if ($e->getMessage() === 'Invalid event type.') {\n        // log raw body, ack with success to avoid redelivery storms\n        return 'success';\n    }\n    throw $e;\n}","preventionTips":["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"],"tags":["wechat-pay","webhook","event-type","message-parsing"],"backgroundTag":"webhook-event-type-missing","analyzedSha":"f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8","analyzedAt":"2026-08-21T05:29:19.565Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}