📋 Overview
When querying the latest captured request for a newly created token (or any token that has not yet received requests) using the endpoint GET /token/{tokenId}/request/latest, the application returns a 500 Internal Server Error instead of an expected 404 Not Found JSON response.
🔍 Root Cause Analysis
The bug resides in app/Http/Controllers/RequestController.php inside the latest() method (lines 185–201):
/**
* Get the latest request associated with a token.
*
* @param HttpRequest $httpRequest
* @param string $tokenId
* @return JsonResponse
*
* @throws NotFoundHttpException
*/
public function latest(HttpRequest $httpRequest, string $tokenId): JsonResponse
{
$token = $this->tokens->find($tokenId);
$requests = $this->requests->all(
$token,
1,
1,
'newest'
);
if (empty($requests)) {
throw new NotFoundHttpException('Request not found');
}
return new JsonResponse($requests[0]);
}
There are two distinct defects in this implementation:
1. Ineffective Emptiness Check on Illuminate\Support\Collection
- The method
$this->requests->all($token, 1, 1, 'newest') returns an instance of Illuminate\Support\Collection.
- In PHP, calling
empty($object) on any instantiated object always evaluates to false, even if the collection contains zero elements.
- Because
empty($requests) evaluates to false, the if guard is skipped when there are no requests. Execution proceeds to return new JsonResponse($requests[0]);. Accessing offset 0 on an empty collection attempts to read an uninitialized array offset (null or Undefined offset: 0), resulting in unintended behavior.
2. Missing Namespace Import for NotFoundHttpException
- The docblock specifies
@throws NotFoundHttpException, but NotFoundHttpException is not imported in RequestController.php via a use statement.
- When
throw new NotFoundHttpException('Request not found'); is reached, PHP attempts to instantiate App\Http\Controllers\NotFoundHttpException.
- Since this class does not exist in the controller's namespace, a fatal error is raised:
Fatal error: Uncaught Error: Class "App\Http\Controllers\NotFoundHttpException" not found in /var/www/html/app/Http/Controllers/RequestController.php
- In production mode, this causes Laravel's exception handler to return a
500 Internal Server Error ({"success": false, "error": {"message": "An internal error occurred"}}).
🔁 Steps to Reproduce
-
Create a fresh token:
curl -s -X POST http://localhost:8084/token
Example Response:
{"uuid": "3fa85f64-5717-4562-b3fc-2c963f66afa6", ...}
-
Query the latest request before sending any webhooks to it:
curl -i http://localhost:8084/token/3fa85f64-5717-4562-b3fc-2c963f66afa6/request/latest
-
Observe the result:
- Actual Response:
HTTP/1.1 500 Internal Server Error
- Expected Response:
HTTP/1.1 404 Not Found with {"success": false, "error": {"message": "Request not found"}}
🛠️ Proposed Fix / Patch
1. Add Missing Import to app/Http/Controllers/RequestController.php:
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
2. Replace empty($requests) and $requests[0] with Collection Methods:
Use $requests->isEmpty() and $requests->first().
Unified Diff:
--- a/app/Http/Controllers/RequestController.php
+++ b/app/Http/Controllers/RequestController.php
@@ -11,6 +11,7 @@
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request as HttpRequest;
use Illuminate\Http\Response;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class RequestController extends Controller
{
@@ -193,11 +194,11 @@ public function latest(HttpRequest $httpRequest, string $tokenId): JsonResponse
'newest'
);
- if (empty($requests)) {
+ if ($requests->isEmpty()) {
throw new NotFoundHttpException('Request not found');
}
- return new JsonResponse($requests[0]);
+ return new JsonResponse($requests->first());
}
}
🧪 Unit Test
This test can be added to tests/RequestControllerTest.php to verify the fix and prevent regressions:
public function testLatestRequestNotFoundReturns404()
{
$this->withoutMiddleware();
$tokenResponse = $this->json('POST', 'token');
$tokenId = $tokenResponse->json()['uuid'];
// Requesting latest for a token with 0 requests should return 404
$response = $this->json('GET', "token/{$tokenId}/request/latest");
$response->assertStatus(404);
}
📋 Overview
When querying the latest captured request for a newly created token (or any token that has not yet received requests) using the endpoint
GET /token/{tokenId}/request/latest, the application returns a500 Internal Server Errorinstead of an expected404 Not FoundJSON response.🔍 Root Cause Analysis
The bug resides in
app/Http/Controllers/RequestController.phpinside thelatest()method (lines 185–201):There are two distinct defects in this implementation:
1. Ineffective Emptiness Check on
Illuminate\Support\Collection$this->requests->all($token, 1, 1, 'newest')returns an instance ofIlluminate\Support\Collection.empty($object)on any instantiated object always evaluates tofalse, even if the collection contains zero elements.empty($requests)evaluates tofalse, theifguard is skipped when there are no requests. Execution proceeds toreturn new JsonResponse($requests[0]);. Accessing offset0on an empty collection attempts to read an uninitialized array offset (nullorUndefined offset: 0), resulting in unintended behavior.2. Missing Namespace Import for
NotFoundHttpException@throws NotFoundHttpException, butNotFoundHttpExceptionis not imported inRequestController.phpvia ausestatement.throw new NotFoundHttpException('Request not found');is reached, PHP attempts to instantiateApp\Http\Controllers\NotFoundHttpException.500 Internal Server Error({"success": false, "error": {"message": "An internal error occurred"}}).🔁 Steps to Reproduce
Create a fresh token:
Example Response:
{"uuid": "3fa85f64-5717-4562-b3fc-2c963f66afa6", ...}Query the latest request before sending any webhooks to it:
Observe the result:
HTTP/1.1 500 Internal Server ErrorHTTP/1.1 404 Not Foundwith{"success": false, "error": {"message": "Request not found"}}🛠️ Proposed Fix / Patch
1. Add Missing Import to
app/Http/Controllers/RequestController.php:2. Replace
empty($requests)and$requests[0]with Collection Methods:Use
$requests->isEmpty()and$requests->first().Unified Diff:
🧪 Unit Test
This test can be added to
tests/RequestControllerTest.phpto verify the fix and prevent regressions: