-
-
Notifications
You must be signed in to change notification settings - Fork 19
Description
When submitting performance traces to the Flare API, the CurlSender incorrectly throws a ConnectionError with message "Invalid JSON response received" even though the request was successful.
The Flare API returns HTTP 201 Created with an empty response body for successful trace submissions. However, CurlSender::post() attempts to parse the empty string as JSON, which fails:
$body = json_decode($json, true); // json_decode('') returns null
if (json_last_error() !== JSON_ERROR_NONE) { // JSON_ERROR_SYNTAX
throw new ConnectionError('Invalid JSON response received');
}This error is then silently swallowed by Api::trace() which catches all exceptions:
public function trace(array $payload): void
{
try {
$this->post($payload, FlarePayloadType::Trace);
} catch (Throwable) {
// Silent failure - no indication that traces aren't being sent
}
}Steps to Reproduce
- Configure Flare with performance monitoring enabled
- Use
AlwaysSampleror wait for sampling to trigger - Make a request that generates a trace
Expected Behavior
Traces should be successfully submitted to Flare and interpreted as succesful.
Actual Behavior
Traces silently fail to submit because CurlSender throws an exception when parsing the empty 201 response body.
Environment
- flare-client-php version: 2.8.0
- PHP version: 8.2
- Framework: WordPress (non-Laravel usage)
Suggested Fix
Check for empty response bodies before attempting JSON parsing:
// Handle empty responses (e.g., 201 Created with no body)
$body = [];
if (trim($json) !== '') {
$body = json_decode($json, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new ConnectionError('Invalid JSON response received');
}
}Example:
$json = curl_exec($curlHandle);
if (is_bool($json)) {
throw new ConnectionError(curl_error($curlHandle));
}
- $body = json_decode($json, true);
-
- if (json_last_error() !== JSON_ERROR_NONE) {
- throw new ConnectionError('Invalid JSON response received');
+ // Handle empty responses (e.g., 201 Created with no body)
+ $body = [];
+ if (trim($json) !== '') {
+ $body = json_decode($json, true);
+
+ if (json_last_error() !== JSON_ERROR_NONE) {
+ throw new ConnectionError('Invalid JSON response received');
+ }
}
$headers = curl_getinfo($curlHandle);Additional Context
This bug is particularly insidious because:
- Error reporting works fine (errors return proper JSON responses)
- The trace collection code works correctly (sampling, spans, etc.)
- The exception is silently caught, so there's no indication of failure
- Debugging requires adding manual logging to the vendor code to discover the issue
I discovered this by adding debug logging throughout the Flare client and observing:
- HTTP status: 201 (success!)
- Response body: empty string
- Result:
ConnectionErrorthrown and silently caught
Workaround
Create a custom sender that extends CurlSender and overrides the post() method with the fix:
class FixedCurlSender extends CurlSender
{
public function post(string $endpoint, string $apiToken, array $payload, FlarePayloadType $type, Closure $callback): void
{
// ... same as parent, but with empty response handling fix
}
}Then configure Flare to use it:
FlareConfig::make(apiToken: $apiToken)
->sendUsing(FixedCurlSender::class)
// ... rest of config