symfony/symfony · error · LogicException
The request was not redirected.
Error message
The request was not redirected.
What it means
Thrown by AbstractBrowser::followRedirect() (line 551) when called but the most recent request did not produce a redirect - i.e. $this->redirect was never set (the response status was not 3xx without a Location header, or followRedirects was off and the property stayed null). The contract is: you can only followRedirect() after a request that actually redirected.
Source
Thrown at src/Symfony/Component/BrowserKit/AbstractBrowser.php:551
}
/**
* Reloads the current browser.
*/
public function reload(): Crawler
{
return $this->requestFromRequest($this->history->current(), false);
}
/**
* Follow redirects?
*
* @throws LogicException If request was not a redirect
*/
public function followRedirect(): Crawler
{
if (!isset($this->redirect)) {
throw new LogicException('The request was not redirected.');
}
if (-1 !== $this->maxRedirects) {
if ($this->redirectCount > $this->maxRedirects) {
$this->redirectCount = 0;
throw new LogicException(\sprintf('The maximum number (%d) of redirections was reached.', $this->maxRedirects));
}
}
$request = $this->internalRequest;
if (\in_array($this->internalResponse->getStatusCode(), [301, 302, 303], true)) {
$method = 'GET';
$files = [];
$content = null;
} else {
$method = $request->getMethod();
$files = $request->getFiles();View on GitHub (pinned to 698e28026c)
Solutions
- Check the response status before following: `if ($client->getInternalResponse()->getStatusCode() >= 300 && < 400) { $client->followRedirect(); }`.
- Inspect `$client->getInternalResponse()->getHeader('Location')` to confirm a redirect exists.
- If using `followRedirects(false)`, only call followRedirect() after verifying a 3xx response.
- Avoid calling followRedirect() after auto-following has already consumed the redirect.
Example fix
// before
$client->followRedirects(false);
$client->request('GET', '/maybe-redirect');
$client->followRedirect(); // may throw if not a redirect
// after
$client->followRedirects(false);
$client->request('GET', '/maybe-redirect');
if (in_array($client->getInternalResponse()->getStatusCode(), [301,302,303,307,308], true)) {
$client->followRedirect();
} Defensive patterns
Strategy: validation
Validate before calling
$client->followRedirects(false);
$client->request('GET', '/maybe-redirect');
$status = $client->getInternalResponse()->getStatusCode();
if ($status >= 300 && $status < 400 && null !== $client->getInternalResponse()->getHeader('Location')) {
$client->followRedirect();
} Type guard
function clientHasPendingRedirect(\Symfony\Component\BrowserKit\AbstractBrowser $c): bool {
$r = new \ReflectionObject($c);
$prop = $r->getProperty('redirect');
if (!$prop->isInitialized($c)) {
return false;
}
return null !== $prop->getValue($c);
} Try / catch
try {
$client->followRedirect();
} catch (\Symfony\Component\BrowserKit\Exception\LogicException $e) {
if (str_contains($e->getMessage(), 'was not redirected')) {
// not a redirect; assert on the actual response
} else {
throw $e;
}
} Prevention
- Before followRedirect(), assert the response status is 3xx.
- When using followRedirects(false), always check status before following.
- Avoid calling followRedirect() after the client has already auto-followed.
When it happens
Trigger: Calling `$client->followRedirect()` manually after a request that returned a 2xx response; calling it twice (the second time the redirect has already been consumed); calling it when followRedirects was off and the previous response had no Location header.
Common situations: Tests that assume a route redirects but it returns 200; calling followRedirect() after the client already auto-followed; misordered assertions where followRedirect runs against a non-redirect response; redirects disabled via `$client->followRedirects(false)` then forgetting to check the status.
Related errors
- The "request()" method must be called before "%s()".
- To insulate requests, you need to override the getScript() m
- Unable to isolate requests as the Symfony Process Component
- There is no button with "%s" as its content, id, value or na
- OUTPUT: %s ERROR OUTPUT: %s.
AI-assisted analysis of symfony/symfony@698e28026c (2026-08-06).
Data as JSON: /api/errors/b1f9c9dc1d5af70d.
Report an issue: GitHub.