laravel/framework · error · HttpException
Service Unavailable
Error message
Service Unavailable
What it means
Thrown as an HttpException (default status 503) by PreventRequestsDuringMaintenance when the app's maintenance mode is active, the request carries no valid bypass cookie/secret, and the maintenance data has no 'template' or 'redirect' key to render instead. It is the fallback 'down for maintenance' response.
Source
Thrown at src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php:101
if (isset($data['redirect']) && ! $request->expectsJson()) {
$path = $data['redirect'] === '/'
? $data['redirect']
: trim($data['redirect'], '/');
if ($request->path() !== $path) {
return redirect($path);
}
}
if (isset($data['template']) && ! $request->expectsJson()) {
return response(
$data['template'],
$data['status'] ?? 503,
$this->getHeaders($data)
);
}
throw new HttpException(
$data['status'] ?? 503,
'Service Unavailable',
null,
$this->getHeaders($data)
);
}
return $next($request);
}
/**
* Determine if the incoming request has a maintenance mode bypass cookie.
*
* @param \Illuminate\Http\Request $request
* @param array $data
* @return bool
*/
protected function hasValidBypassCookie($request, array $data)View on GitHub (pinned to deac04fbdc)
Solutions
- Run php artisan up to disable maintenance mode.
- Provide a maintenance template via php artisan down --render='errors::503' (or a custom view) so a page renders instead of a bare exception.
- Add critical paths to PreventRequestsDuringMaintenance::except() so health checks/API still work.
- Use php artisan down --secret=... and visit the secret URL to obtain the bypass cookie for testing during downtime.
Example fix
// before php artisan down // bare maintenance, no template -> HttpException 503 // after php artisan down --render='errors::maintenance' --retry=60 php artisan up // when deploy complete
Defensive patterns
Strategy: try-catch
Try / catch
try {
$response = $kernel->handle($request);
} catch (\Symfony\Component\HttpKernel\Exception\HttpException $e) {
if ($e->getStatusCode() === 503) {
return response()->json(['message' => 'Maintenance in progress.', 'retry' => $e->getHeaders()['Retry-After'] ?? null], 503);
}
throw $e;
} Prevention
- Always run php artisan up after deploys (automate it in your deploy script).
- Render a maintenance template so users see a page, not a bare exception.
- Exclude health-check and status endpoints via PreventRequestsDuringMaintenance::except().
- Use a maintenance secret for safe testing during downtime.
When it happens
Trigger: Running php artisan down and then hitting any non-excluded route without the bypass cookie; the maintenance payload containing only status/retry without a template; a request that does not match the secret bypass path and lacks the laravel_maintenance cookie.
Common situations: Forgot to take the app out of maintenance (php artisan up) after a deploy; custom maintenance payload that omits 'template'; deploy scripts that run down but fail before up; CI hitting the app during a maintenance window.
Understand the failure class
- HTTP status errors: handling 4xx and 5xx responses — how to handle 4xx and 5xx responses properly.
Related errors
- Please implement the prunable method on your model.
- Please implement the prunable method on your model.
- Dump execution exceeded maximum depth of 30.
- Schema dumping is not supported when using SQL Server.
- Your configuration files could not be serialized because the
AI-assisted analysis of laravel/framework@deac04fbdc (2026-08-06).
Data as JSON: /api/errors/b37adf6c8918d00b.
Report an issue: GitHub.