laravel/framework · error · Exception
Concurrent process failed with exit code [$result->exitCode(
Error message
Concurrent process failed with exit code [$result->exitCode()]. Message: $result->errorOutput()
What it means
Thrown by ProcessDriver::run() when any process in the pool exits with a failure status. The process driver serializes closures and runs them via the artisan invoke-serialized-closure command in a pool; if a child process crashes (non-zero exit code), the driver collects errorOutput() and rethrows as an Exception with the exit code and stderr.
Source
Thrown at src/Illuminate/Concurrency/ProcessDriver.php:53
$command = Application::formatCommandString('invoke-serialized-closure');
$results = $this->processFactory->pool(function (Pool $pool) use ($tasks, $command, $timeout) {
foreach (Arr::wrap($tasks) as $key => $task) {
$process = $pool->as($key)->path(base_path())->env([
'LARAVEL_INVOKABLE_CLOSURE' => base64_encode(
serialize(new SerializableClosure($task))
),
])->command($command);
if (! is_null($timeout)) {
$process->timeout($timeout);
}
}
})->start()->wait();
return $results->collect()->mapWithKeys(function ($result, $key) {
if ($result->failed()) {
throw new Exception('Concurrent process failed with exit code ['.$result->exitCode().']. Message: '.$result->errorOutput());
}
$output = $result->output();
if (($pos = strpos($output, "\x1f\x8b")) !== false) {
$output = substr($output, 0, $pos);
}
$result = json_decode($output, true);
if (! $result['successful']) {
throw new $result['exception'](
...(! empty(array_filter($result['parameters'], fn ($parameter) => ! is_null($parameter)))
? $result['parameters']
: [$result['message']])
);
}
View on GitHub (pinned to bd6b5437e6)
Solutions
- Inspect the embedded errorOutput() in the message for the child's stderr/stack trace.
- Run the same closure synchronously (sync driver) to reproduce the underlying error.
- Ensure closures only capture serializable values and the artisan bootstrap is identical for workers.
Example fix
// before
$concurrency->run([
fn () => $heavyService->process($job), // throws in child
]);
// after
$concurrency->driver('sync')->run([
fn () => $heavyService->process($job), // reproduce locally first
]); Defensive patterns
Strategy: fallback
Validate before calling
// reproduce synchronously first to validate the closure
try {
app(\Illuminate\Concurrency\ConcurrencyManager::class)->driver('sync')->run($tasks);
} catch (\Throwable $e) {
throw new \RuntimeException('Task fails in sync mode: '.$e->getMessage(), 0, $e);
} Try / catch
try {
$results = $concurrency->run($tasks);
} catch (\Exception $e) {
// $e->getMessage() contains child exit code + errorOutput()
$results = $concurrency->driver('sync')->run($tasks);
} Prevention
- Validate closures in sync mode before running them concurrently.
- Only capture serializable values in closures (avoid PDO statements, open resources, service singletons).
- Keep the PHP version and extensions identical between dispatcher and worker processes.
When it happens
Trigger: Passing a closure that throws an exception, fatals, runs out of memory, or references unserializable/non-existent symbols. Also environment issues: missing artisan binary, wrong working directory, deserialization mismatch between parent and child PHP environments.
Common situations: Closure capturing an unserializable object. PHP version/extension mismatch between the dispatching process and the spawned workers. A closure that hits a fatal error (class not found, permission denied) inside the child.
Related errors
- Due to PHP limitations, the fork driver may not be used with
- Please install the "spatie/fork" Composer package in order t
- Callback must be a callable, callback array, or a 'Class@met
- Auth guard [{$name}] is not defined.
- Auth driver [{$config['driver']}] for guard [{$name}] is not
AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06).
Data as JSON: /data/errors/34c98d23a9dd15bf.json.
Report an issue: GitHub.