Description
The send() method in DiscordWebhook.php throws a TypeError when Discord's API returns an error response (HTTP 400-599).
Error message:
TypeError: json_decode(): Argument #1 ($json) must be of type string, true given
Stack trace:
#0 vendor/atakde/discord-webhook-php/src/DiscordWebhook.php(79): json_decode()
#1 App\Queue\Task\ChatLogTask.php(40): Atakde\DiscordWebhook\DiscordWebhook->send()
Root Cause
The send() method does not set the CURLOPT_RETURNTRANSFER option before calling curl_exec().
Without this option:
curl_exec() returns true (boolean) on success instead of returning the response body as a string
- When Discord returns an error response (e.g., 404, 400, 429), the code attempts to decode this boolean value on line 79
- This causes a
TypeError in PHP 8.0+
Current Code (Buggy)
public function send(): bool
{
try {
$ch = curl_init($this->webhookUrl);
// is multipart/form-data
if ($this->isMultipart()) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->message->toArray());
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: multipart/form-data']);
} else {
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->message->toJson());
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($this->message->toJson())
));
}
$response = curl_exec($ch); // Returns TRUE instead of response string!
$responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($responseCode >= 200 && $responseCode < 300) {
return true;
} else {
$decodedResponse = json_decode($response, true); // TypeError: trying to decode TRUE
throw new InvalidResponseException($decodedResponse["message"] ?? "Error ocurred!", $responseCode);
}
} catch (\Exception $e) {
// suppress exception if debug is false
if ($this->debug) {
throw $e;
}
return false;
}
}
Steps to Reproduce
- Set up a Discord webhook with an invalid URL or one that will return an error
- Attempt to send a message using the library
- When Discord returns an HTTP error (400-599), the TypeError occurs
Alternatively, to reproduce without Discord:
$messageFactory = new MessageFactory();
$textMessage = $messageFactory->create('text');
$textMessage->setUsername('Test-Bot');
$textMessage->setContent('Test message');
$webhook = new DiscordWebhook($textMessage);
$webhook->setWebhookUrl('https://discord.com/api/webhooks/invalid/webhook'); // Invalid URL
$webhook->send(); // Will throw TypeError when Discord returns 404
Expected Behavior
The method should properly handle error responses from Discord without throwing TypeErrors.
Proposed Fix
Add CURLOPT_RETURNTRANSFER option and handle empty/false responses:
public function send(): bool
{
try {
$ch = curl_init($this->webhookUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // FIX: Add this line
// is multipart/form-data
if ($this->isMultipart()) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->message->toArray());
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: multipart/form-data']);
} else {
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->message->toJson());
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($this->message->toJson())
));
}
$response = curl_exec($ch);
$responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($responseCode >= 200 && $responseCode < 300) {
return true;
} else {
// FIX: Handle false/empty responses gracefully
$decodedResponse = json_decode($response ?: '{}', true);
throw new InvalidResponseException($decodedResponse["message"] ?? "Error ocurred!", $responseCode);
}
} catch (\Exception $e) {
// suppress exception if debug is false
if ($this->debug) {
throw $e;
}
return false;
}
}
Environment
- Library version: 2.0.0
- PHP version: 8.3+ (but affects all PHP 8.x versions with type checking)
- Operating System: Linux
Additional Notes
This bug has existed since the library was created but only manifests when Discord returns error responses. Many users may not have encountered it if their webhooks always succeed.
The fix is a simple two-line change:
- Add
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); after curl_init()
- Change
json_decode($response, true) to json_decode($response ?: '{}', true)
Workaround
Until this is fixed, users can create a wrapper class that extends DiscordWebhook and overrides the send() method with the corrected implementation.
Description
The
send()method inDiscordWebhook.phpthrows aTypeErrorwhen Discord's API returns an error response (HTTP 400-599).Error message:
Stack trace:
Root Cause
The
send()method does not set theCURLOPT_RETURNTRANSFERoption before callingcurl_exec().Without this option:
curl_exec()returnstrue(boolean) on success instead of returning the response body as a stringTypeErrorin PHP 8.0+Current Code (Buggy)
Steps to Reproduce
Alternatively, to reproduce without Discord:
Expected Behavior
The method should properly handle error responses from Discord without throwing TypeErrors.
Proposed Fix
Add
CURLOPT_RETURNTRANSFERoption and handle empty/false responses:Environment
Additional Notes
This bug has existed since the library was created but only manifests when Discord returns error responses. Many users may not have encountered it if their webhooks always succeed.
The fix is a simple two-line change:
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);aftercurl_init()json_decode($response, true)tojson_decode($response ?: '{}', true)Workaround
Until this is fixed, users can create a wrapper class that extends
DiscordWebhookand overrides thesend()method with the corrected implementation.