Laravel 13.30: chunkBy() and Storage Path Hardening | Mohamed Said       [Skip to content](#main)  [ ![](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png) Mohamed SaidLaravel Backend Engineer ](https://www.msaied.com/public) - [Home](https://www.msaied.com/public)
- [Projects](https://www.msaied.com/public/projects)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [About](https://www.msaied.com/public#about)

           [  Contact](https://www.msaied.com/public#contact) Menu 

Menu
----

Close 

 - [HomeStart here](https://www.msaied.com/public)
- [ProjectsCase studies](https://www.msaied.com/public/projects)
- [ArticlesEngineering notes](https://www.msaied.com/public/articles)
- [CertificatesCredentials](https://www.msaied.com/public/certificates)
- [AboutHow I work](https://www.msaied.com/public#about)
- [ContactGet in touch](https://www.msaied.com/public#contact)

  [Start a conversation](https://www.msaied.com/public#contact) [WhatsApp](https://wa.me/201094619204) [Email](mailto:hello@msaied.com) 

 1. [Home](https://www.msaied.com/public)
2. /
3. [Articles](https://www.msaied.com/public/articles)
4. /
5. [Laravel](https://www.msaied.com/public/articles?category=laravel)
6. /
7. Collections chunkBy() and Storage Path Hardening in Laravel 13.30

   [Laravel](https://www.msaied.com/public/articles?category=laravel) 

 Collections chunkBy() and Storage Path Hardening in Laravel 13.30
==================================================================

 Laravel 13.30 ships chunkBy() for grouping adjacent collection items, closes a path-traversal gap in Storage::path(), and prints queue worker stop reasons directly in console output.

 ![](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp) [Mohamed Said](https://www.msaied.com/public#person) Published 1 Sep 2026 · Updated 2 Sep 2026 · 3 min read

ShareCopy linkCopied

 ![Collections chunkBy() and Storage Path Hardening in Laravel 13.30](https://cdn.msaied.com/622/59bd72aa94848dfb195df6dcfb498e43.png) 

  On this page +1. [What's New in Laravel 13.30](#whats-new-in-laravel-1330)
2. [chunkBy() for Collections and Lazy Collections](#codechunkbycode-for-collections-and-lazy-collections)
3. [Storage::path() Now Rejects Path Traversal](#codestoragepathcode-now-rejects-path-traversal)
4. [Worker Stop Reasons in queue:work](#worker-stop-reasons-in-codequeueworkcode)
5. [Other Notable Changes](#other-notable-changes)
6. [Key Takeaways](#key-takeaways)

 What's New in Laravel 13.30
---------------------------

Laravel 13.30 landed on September 2, 2026 with a focused set of developer-experience improvements and one notable security hardening. Here is a breakdown of the headline changes.

---

### `chunkBy()` for Collections and Lazy Collections

The existing `chunkWhile()` method splits a collection whenever a callback returns `false`. The most common pattern was comparing the current item against the last item in the chunk being built:

```php
$products->chunkWhile(
    fn ($value, $key, $chunk) => $value->parent == $chunk->last()->parent
);

```

The new `chunkBy()` method encodes that comparison directly. Pass a key name or a callback, and a new chunk starts whenever the resolved value changes:

```php
$products->chunkBy('parent');

collect([1, 1, 2, 2, 1, 1])->chunkBy(fn ($value) => $value);
// [[1, 1], [2, 2], [1, 1]]

```

The key is resolved through `data_get()`, so dot notation works (`chunkBy('address.city')`). Original keys are preserved inside each chunk. Contributed by [@JosephSilber](https://github.com/JosephSilber) in [\#61357](https://github.com/laravel/framework/pull/61357).

---

### `Storage::path()` Now Rejects Path Traversal

Every Flysystem-backed filesystem call normalizes paths and throws `PathTraversalDetected` when a path resolves outside the disk root — except `Storage::path()`, which previously just concatenated the prefix:

```php
Storage::get('../../../.env');  // rejected
Storage::path('../../../.env'); // resolved outside the disk root

```

This mattered anywhere user input reached `path()`, for example:

```php
response()->download(Storage::path($request->query('path')));

```

`path()` now runs the argument through `WhitespacePathNormalizer` — the same normalizer every other Flysystem call uses — before prefixing. Anything that escapes the disk root throws `PathTraversalDetected`. Code relying on `..` segments in `path()` will now receive an exception. Contributed by [@KIKOmanasijev](https://github.com/KIKOmanasijev) in [\#61343](https://github.com/laravel/framework/pull/61343).

---

### Worker Stop Reasons in `queue:work`

`queue:work` now prints the reason a worker exits as its final line:

```yaml
2026-09-01 13:20:40 Worker STOPPED Memory limit exceeded

```

With `--json`, the reason is emitted as a structured record:

```json
{"level":"warning","status":"stopped","reason":"memory","exit_code":12,"jobs_processed":2,"memory":1.2,"timestamp":"2026-09-01T13:20:40.118273+00:00"}

```

Nine exit scenarios are covered, including memory limit exceeded, maximum jobs exceeded, restart signal received, and job timed out. Nothing is written under `--quiet` or `--silent`. Contributed by [@jackbayliss](https://github.com/jackbayliss) in [\#61339](https://github.com/laravel/framework/pull/61339).

---

### Other Notable Changes

- **`DevCommands::withoutVendorCommands()` / `withoutDefaultCommands()`** — filter `dev` commands by origin instead of naming every command explicitly.
- **Native `sqlsrv:` DSN strings** — `sqlsrv:Server=host,1433;Database=db;Encrypt=true` is now parsed correctly instead of being mangled by `parse_url()`.
- **`Artisan::commandNamed()`** — resolves a single command by name without constructing every registered command.
- **Cloud queue totals** — `totalPendingSize()`, `totalDelayedSize()`, and `totalReservedSize()` are now implemented on the Laravel Cloud queue driver.
- **`route:cache` facade fix** — the global facade application is restored after `route:cache` bootstraps its throwaway container, preventing `Route is not bound` errors during `php artisan optimize`.
- **`Request::clamp()` non-numeric fallback** — inputs like `?per-page=foo` now fall through to the default instead of returning a 500.

---

Key Takeaways
-------------

- `chunkBy()` replaces verbose `chunkWhile()` callbacks when grouping by a stable key or computed value.
- `Storage::path()` now enforces the same path-traversal protection as every other storage method — audit any code that passes user input to `path()`.
- Queue worker exit reasons appear in console output without any listener setup.
- Native SQL Server DSN strings are parsed correctly for the first time.
- `Artisan::commandNamed()` avoids the performance cost of constructing all commands just to find one.

---

[Source: Laravel News — Laravel 13.30.0](https://laravel-news.com/laravel-13-30-0)

- [Laravel 13.30](https://www.msaied.com/public/articles?search=Laravel%2013.30)
- [Collections](https://www.msaied.com/public/articles?search=Collections)
- [Storage](https://www.msaied.com/public/articles?search=Storage)
- [Queue](https://www.msaied.com/public/articles?search=Queue)
- [Security](https://www.msaied.com/public/articles?search=Security)

 Frequently asked questions 
---------------------------

  What is the difference between chunkBy() and chunkWhile() in Laravel collections?`chunkWhile()` splits a collection wherever a callback returns false, requiring you to manually compare the current item with the last item in the current chunk. `chunkBy()` wraps that pattern: you pass a key name or callback, and a new chunk starts automatically whenever the resolved value changes. It also supports dot notation via `data\_get()`.

   Why is the Storage::path() change in Laravel 13.30 a security improvement?Before 13.30, `Storage::path()` skipped path normalization and simply concatenated the disk prefix with the given string. This meant passing `../../../.env` returned a valid native path outside the disk root, even though `Storage::get()` and other methods would have rejected the same input. The fix runs the argument through `WhitespacePathNormalizer` and throws `PathTraversalDetected` for any path that escapes the disk root, matching the behavior of every other filesystem call.

   How do I see why a Laravel queue worker stopped without registering a listener?In Laravel 13.30 and later, `queue:work` prints the stop reason as its final line automatically, for example `Worker STOPPED Memory limit exceeded`. With the `--json` flag the reason is included in a structured JSON record. Nothing is output under `--quiet` or `--silent`.

   ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)About the author
----------------

[Mohamed Said](https://www.msaied.com/public#person)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

[About](https://www.msaied.com/public#about) [GitHub ↗](https://github.com/EG-Mohamed) [LinkedIn ↗](https://www.linkedin.com/in/msaiedm/) [WhatsApp ↗](https://wa.me/201094619204) [Email Address ↗](mailto:hello@msaied.com) [My CV ↗](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)  

   [Previous articleFilament v3 Table Tricks: Deferred Loading, Live Search, and Custom Filter Forms](https://www.msaied.com/public/articles/filament-v3-table-tricks-deferred-loading-live-search-and-custom-filter-forms) [Next articleLivewire v3 Performance: Computed Properties, Dehydration Budgets, and Wire:model Lazy](https://www.msaied.com/public/articles/livewire-v3-performance-computed-properties-dehydration-budgets-and-wiremodel-lazy)  

   On this page
-------------

1. [What's New in Laravel 13.30](#whats-new-in-laravel-1330)
2. [chunkBy() for Collections and Lazy Collections](#codechunkbycode-for-collections-and-lazy-collections)
3. [Storage::path() Now Rejects Path Traversal](#codestoragepathcode-now-rejects-path-traversal)
4. [Worker Stop Reasons in queue:work](#worker-stop-reasons-in-codequeueworkcode)
5. [Other Notable Changes](#other-notable-changes)
6. [Key Takeaways](#key-takeaways)

 ###  Have a technical challenge?

 Tell me what you’re building. I reply within two working days.

[Start a conversation](https://www.msaied.com/public#contact) 

   Related articles
-----------------

 [ ![](https://cdn.msaied.com/740/cce86edc21eddcbdd2f2454fadaf9c70.png)  · 3 min read### The Pipeline Pattern in Laravel: Custom Pipelines Beyond Middleware

5 Oct 2026 ](https://www.msaied.com/public/articles/the-pipeline-pattern-in-laravel-custom-pipelines-beyond-middleware-1) [ ![](https://cdn.msaied.com/739/2d6897fdcdcf090613f96f72a64b8a78.png)  · 4 min read### MySQL Full-Text Search in Laravel: Indexes, Relevance Scoring, and Boolean Mode

4 Oct 2026 ](https://www.msaied.com/public/articles/mysql-full-text-search-in-laravel-indexes-relevance-scoring-and-boolean-mode) [ ![](https://cdn.msaied.com/738/073696a3fefe18bec825beec5ac658f5.png)  · 4 min read### Laravel Queue Rate-Limited Middleware: Throttling Jobs Without Losing Work

4 Oct 2026 ](https://www.msaied.com/public/articles/laravel-queue-rate-limited-middleware-throttling-jobs-without-losing-work) 

  Have a technical challenge?
----------------------------

Tell me what you’re building. I reply within two working days.

 [Discuss your project ↗](https://www.msaied.com/public#contact) 

  © 2026 Mohamed Said · Built with Laravel, meant to last.Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

 - [Home](https://www.msaied.com/public)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [GitHub](https://github.com/EG-Mohamed)
- [LinkedIn](https://www.linkedin.com/in/msaiedm/)
- [WhatsApp](https://wa.me/201094619204)
- [Email Address](mailto:hello@msaied.com)
- [My CV](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
- [Sitemap](https://www.msaied.com/public/sitemap.xml)
