Laravel 13.34.0 was published on September 30, 2026. The release changes queue failure handling and adds smaller improvements across the ORM, schema tools, testing helpers, cache, and platform integrations.

ProcessPodcast.php
use Illuminate\Queue\Attributes\CountCrashesAsExceptions;
use Illuminate\Queue\Attributes\MaxExceptions;

#[MaxExceptions(3), CountCrashesAsExceptions]
class ProcessPodcast implements ShouldQueue
{
    public function retryUntil(): DateTime
    {
        return now()->addHour();
    }
}

William Julian-Vicary added the opt-in CountCrashesAsExceptions attribute for queued jobs. Laravel already counted a thrown exception toward a job's $maxExceptions value. A worker killed by an out-of-memory condition, a segmentation fault, or a stopped container did not count as an exception, which could allow a retryUntil() job using a rate limiter to keep crashing workers until its deadline.

The new attribute counts a crashed attempt as one exception. A public $countCrashesAsExceptions = true property provides the same behavior. The worker writes a cache key when it starts an opted-in job and removes that key when the attempt finishes. If the key remains at the next attempt, Laravel treats the earlier attempt as a worker crash. The job must define maxExceptions, and every attempt adds two cache operations. That overhead is why the behavior is disabled by default. The change was tracked in pull request #61737.

Jack Bayliss changed timeout handling for jobs implementing Illuminate\Contracts\Queue\Interruptible. The worker now sends SIGALRM when the job reaches its timeout, allowing interrupted() to save progress before the job fails. Earlier releases sent signals such as SIGTERM for other interruptions, while a timeout could terminate the worker without notifying the job.

The worker also dispatches JobInterrupted, an event introduced in Laravel 13.31. Exceptions raised by interrupted() are reported while the timeout continues. Pull request #61651 contains this change.

JobProcessed now exposes a duration property measured in milliseconds. The value is a float rounded to two decimal places when the event comes from a worker. It is null when code dispatches the event elsewhere. Applications can stop pairing JobProcessing and JobProcessed merely to measure runtime. This was added in pull request #61672.

queue:flush accepts --queue, so operators can remove failed jobs from one queue while leaving failures on other queues intact. The option can be combined with --hours, for example queue:flush --queue=sftp-sync --hours=48, which preserves recent failures. The change is recorded as pull request #61630.

Schema::getColumn('users', 'email') returns metadata for one column. The result includes fields such as type_name and nullable, and the method returns an empty array when the column does not exist. Pull request #61759 added the method.

assertDatabaseCount() now accepts an array of table and count pairs. A test can check several Eloquent models or table names in one assertion. Pull request #61727 covers the change.

App::environment() and the scheduler's environments() method now accept enums. The same applies to the Blade @env directive because it compiles through App::environment(). Queue::isPaused() also accepts enums, matching Queue::pause() and Queue::resume(). Before this update, an enum passed to App::environment() caused an error, while an enum passed to a scheduled task's environments() method prevented the task from running. These changes came through pull requests #61730 and #61725.

Relation::requireMorphMap() now protects the read side of polymorphic relations. Laravel already rejected writes without a morph map entry. Lazy and eager loading now also throws ClassMorphViolationException when a *_type value is absent from the map. Applications that do not enable requireMorphMap() keep their previous behavior. Pull request #61711 introduced the read-side check.

The remaining 13.34.0 changelog includes fixes and compatibility work. LazyCollection values now work in between clauses (#61678), and LazyCollection::combine() raises ValueError for mismatched lengths (#61696). Refreshed attributes are synchronized with the original state after increment or decrement, and are excluded when models are replicated (#61680, #61751). Number::parseInt() handles values above the 32-bit range, while Number::format(), percentage(), and currency() no longer return -0 (#61691, #61716). Collection::mode() ignores null entries correctly (#61686), shift($count) returns an empty collection when the source is empty (#61723), and trans_choice() selects the correct plural form for negative numbers (#61700).

PhpRedisLock::refresh() now works with phpredis serialization enabled (#61690). DatabaseLock no longer hides deadlocks inside transactions (#61708). Numeric sortBy() keeps fractional values when multiple columns and SORT_NUMERIC are used (#61699). Multipart request retries retain attached stream contents (#61728). Eloquent whereNot() no longer applies double negation to array conditions (#61721), and relation queries respect the owner key in whereMorphedTo() and whereNotMorphedTo() (#61712). wherePivotBetween() now works with sync(), detach(), and updateExistingPivot() (#61747). through() no longer returns HasOneThrough for MorphMany relations (#61760), and findOrFail() handles arrays of enum IDs (#61765).

The release fixes queue:restart output for workers that cannot be restarted (#61706). It adds cloud exceptions (#61704), named S3 credential providers and Cloud IAM disks (#61676), and support for phpstan/phpstan:2.2.15 (#61719). Pooled Cloud Postgres keeps existing PDO options when emulated prepares are forced (#61735). Memcached locks lasting more than 30 days no longer expire immediately (#61742), and Redis throttling no longer reports a timestamp as the remaining attempt count (#61748). Queue payload handling received a regression test for createPayloadUsing (#61773).

Blade's elsePushIf directive now handles complex conditions (#61741). ArrayStore::touch() treats dotted keys literally (#61777), and memoized tagged-cache many() no longer returns null for numeric keys (#61780). File reportable details include the MIME type (#61772). Validator exclusions use constant-time lookups (#61698). The release also contains Markdown corrections (#61746), a final Mockery cleanup (#61739), documentation and test updates (#61679, #61683, #61697, #61663), and StyleCI fixes (#61763).

CI workflows now run on Windows 2025, and a flaky Windows scheduling test was corrected (#61718, #61768). Imagick is explicitly enabled for CI tests (#61756).