19 Laravel Bug Fixes — Tested, Verified, Ready to Merge

Update (2026-03-19): This has grown to 91 PRs across 27 repos. See the Day 2 update for the full list with confidence ratings.


I found and fixed 19 bugs across the Laravel ecosystem — 10 Windows-specific and 9 cross-platform. Every fix has been tested on Windows 11 Pro and independently verified on macOS (Darwin 25.3.0, PHP 8.4.19) with bug reproduction, concurrency testing, and full test suite runs.

I'm currently blocked from the Laravel GitHub organisation, so I can't submit PRs or comment on issues.

All patches and PRs are linked below and in the gist — feel free to use them directly. I can't push these upstream because submitting too many at once gets you blocked, and the contribution guide states that AI-generated pull requests will be closed without review. These are 100% AI-generated using Claude Code — every fix was found, written, and tested by AI on my machine.

Full details and patches: GitHub Gist


The Fixes

Cross-Platform (Production Critical)

laravel/cashier-stripe #1759 — Webhook race condition creates duplicate subscriptions. When customer.subscription.created and customer.subscription.updated webhooks arrive simultaneously, both handlers insert a new row. Active data corruption in production. Fix catches UniqueConstraintViolationException and recovers gracefully. Verified with real concurrent processes on both SQLite and PostgreSQL — race triggered 10/10 times, fix recovered every time. Patch

laravel/framework #58207 — OOM jobs retry infinitely. When a job causes an out-of-memory kill, the exception counter never increments because the catch block never executes. Jobs with $maxExceptions retry forever. 31 comments. Fix uses optimistic increment — counter goes up before fire(), down on success. Verified with real OOM kills (PHP exit code 255). Patch

laravel/framework #56395 — Pipeline memory leak. Pipeline::then() retains references to job objects after completion, preventing garbage collection. Workers hold 254MB instead of 4MB after processing 50 jobs. Two-line fix. 22 comments. Patch

laravel/reverb #344 — TypeError crash. Operator precedence bug in isWebSocketRequest() means any non-null Upgrade header is treated as a websocket request. Plus no guard when reverse proxies strip headers. 17 comments, users switching to Soketi. All 126 tests pass including Redis. Patch

laravel/serializable-closure #126 — v2.0.9 regression breaks Bus::chain. Objects with __serialize skip closure wrapping entirely, causing serialization failures. Fix scopes the skip to only Closure-typed properties. 338 tests pass. Patch

laravel/cashier-stripe #1817 — swapAndInvoice gives free upgrades. When payment fails during a plan swap, users end up on the expensive plan for free. Fix adds pendingIfPaymentFails() as the default. Patch

laravel/horizon #1535 — Silent 60-second queue stalls. Memory-exceeded workers restart, die again, then cooldown for 60 seconds with zero logging. Impossible to diagnose. Fix adds logging at 3 critical points. 169 tests pass. Patch

laravel/pulse #461 — Multi-server deadlocks. Concurrent pulse:work processes read the same Redis stream entries and deadlock on MySQL upserts. Fix adds atomic Redis lock around digest. Patch

laravel/framework #57070 — Sub-minute scheduling skips. endOfMinute() mutates the Carbon instance used in the loop condition. Fix uses copy()->endOfMinute(). 68 scheduling tests pass. Patch

Windows-Specific

laravel/octane #1100 — FrankenPHP crashes on Windows. POSIX signal constants don't exist. PR

laravel/wayfinder #128 — Backslash import paths. DIRECTORY_SEPARATOR produces \ in TypeScript. Patch

laravel/sail #843 — Testing database never created. Bash shebang fails in MySQL containers. PR

laravel/sail #850 — Installation fails on Windows. Unrecognised OS. PR

laravel/installer #472laravel new crashes with Boost. No TTY support. Patch

laravel/vs-code-extension #575 — Symlinked packages break. Double path construction. Patch

laravel/prompts #191 — Terminal rendering glitches. PHP_EOL newline miscounting. Patch

laravel/octane #1034 — File watcher ignores --poll. FrankenPHP overrides parent watcher. PR

laravel/sail #815 — Headed browser tests fail. No virtual display. PR

laravel/vite-plugin-wayfinder #10 — Wayfinder fails in Vite. Working directory resolution. Patch


Verification

Every fix was tested on Windows 11 Pro 26200 and macOS Darwin 25.3.0 (PHP 8.4.19). Cross-platform fixes include:

  • Bug reproduction with before/after proof
  • Full test suite runs (2,500+ tests total across all repos)
  • Concurrency testing with pcntl_fork and barrier synchronisation
  • Real OOM kills (PHP memory limit exhaustion, exit code 255)
  • Memory leak measurement (WeakReference + memory profiling)
  • PostgreSQL and Redis integration testing via Docker

All patches, verification data, and test results are in the gist.


EDIT (2026-03-19): The count has grown from 19 to 25 fixes across 11 Laravel repos. Here's what was added:

New Cross-Platform Fixes

laravel/framework #57262incrementEach() updates ALL rows in the table. DATA CORRUPTION — calling $model->incrementEach() on an Eloquent model updates every row, not just that model. Multiple reports of near-production data loss. Fix adds explicit incrementEach()/decrementEach() methods to Eloquent Builder that call toBase() to apply scopes. All 195 builder tests pass. Patch

laravel/framework #58377 — SessionManager creates duplicate Redis connections. Every request with Redis sessions opens 2 connections instead of 1 due to an unnecessary clone. Causes RedisException: Connection limit reached in strict environments. 12 comments. One-line fix — remove the clone. All 93 session tests pass. Patch

laravel/reverb #273 — Presence channels return wrong user list when scaling with Redis. Each Reverb instance maintains its own local member list. Presence events never propagated via Redis pub/sub to other instances. Completely breaks presence channels at scale. Fix routes member events through the Redis event dispatcher and adds a new PRESENCE_DATA metric type for cross-instance member gathering. 237 tests pass. Patch

laravel/octane #1004 — No zero-downtime deployment. octane:reload doesn't work with symlink-based deployments (Deployer, Envoyer). 23 comments, 5-30s downtime per deploy. New ResolvesSymlinks trait detects symlinked directories and ensures all three server types (Swoole, RoadRunner, FrankenPHP) use the symlink path. clearstatcache(true) on reload. 180 tests pass. Patch

laravel/scout #957 — Timeout jobs block queue forever. Scout's MakeSearchable jobs don't set failOnTimeout, so timed-out jobs silently hang in Horizon. One-line fix. All 211 Scout tests pass. Patch

New Windows Fixes

laravel/wayfinder #178, #161, #159 — Three TypeScript generation bugs. #178: Generated .d.ts breaks Inertia type merging (missing import). #161: Dashed route names produce invalid TS identifiers. #159: Route action named "options" shadows the routeOptions parameter. Patch

Updated Fixes

Cashier #1817 (swapAndInvoice) was redesigned. The original pendingIfPaymentFails() approach was incompatible with Stripe's API (rejects tax_rates with pending_if_incomplete — verified with real Stripe test key, 8 API errors). The new fix uses webhook reconciliation: a handleInvoicePaymentFailed() handler detects failed subscription update payments and syncs the local DB back to Stripe's actual state. All 44 feature tests pass with real Stripe API key. PR

Cashier #1759 (duplicate subscriptions) now also has a PR on my fork with the race condition fix verified against real Stripe API — all 44 tests pass. PR

Current Totals