Defect
With durable-workflow/workflow 2.0.3 and PHP 8.4.25, disposing a suspended workflow Fiber executes the workflow's finally block. A durable activity, timer or memo call there tries to suspend an already force-closing Fiber:
FiberError: Cannot suspend in a force-closed fiber
This occurs at an ordinary workflow-task suspension, not only explicit cancellation. A queued workflow containing durable cleanup in finally did not reach its first activity in the reproduction.
Minimal Reproduction
After loading the Composer autoloader:
$execution = Workflow\V2\Support\WorkflowExecution::start(
new class extends Workflow\V2\Workflow {
public function handle(): void
{
try {
Workflow\V2\timer(1);
} finally {
Workflow\V2\timer(1);
}
}
},
[],
);
unset($execution);
The final line throws the FiberError. Reproduced in a fresh PHP process on 2026-09-05.
Acceptance
- Ordinary suspension/disposal must not execute durable cleanup as if the workflow had reached a terminal business path.
- Cover real queued execution and fresh-process replay of activity/timer/memo cleanup after both success and handled failure.
- Define cancellation versus forced termination behavior without claiming cleanup always runs.
- Avoid retaining every suspended Fiber indefinitely as a workaround.
An application can currently use explicit catch-and-cleanup control flow after the try/catch instead of suspending in finally. This avoids the failing disposal path but does not resolve the engine authoring contract.
Accepted product defect, ahead of discretionary coverage expansion.
Defect
With
durable-workflow/workflow 2.0.3and PHP 8.4.25, disposing a suspended workflow Fiber executes the workflow'sfinallyblock. A durable activity, timer or memo call there tries to suspend an already force-closing Fiber:This occurs at an ordinary workflow-task suspension, not only explicit cancellation. A queued workflow containing durable cleanup in
finallydid not reach its first activity in the reproduction.Minimal Reproduction
After loading the Composer autoloader:
The final line throws the FiberError. Reproduced in a fresh PHP process on 2026-09-05.
Acceptance
An application can currently use explicit catch-and-cleanup control flow after the try/catch instead of suspending in
finally. This avoids the failing disposal path but does not resolve the engine authoring contract.Accepted product defect, ahead of discretionary coverage expansion.