Description
_execute_with_timeout in core/engine.py calls future.result(timeout=seconds), which raises concurrent.futures.TimeoutError on expiry. The catch block at lines 134 and 176 catches bare TimeoutError (the builtin).
On Python 3.9 and 3.10, concurrent.futures.TimeoutError is a separate class that inherits directly from Exception, not from builtins.TimeoutError. This means the timeout is never caught on those versions.
Location
dotflow/core/engine.py — lines 134, 170-178
Current Behavior
except TimeoutError:
future.cancel()
raise TimeoutError()
On Python 3.9/3.10, concurrent.futures.TimeoutError propagates uncaught, bypasses retry logic, and the task is marked FAILED with a confusing generic error instead of a proper TimeoutError.
Expected Behavior
Both builtins.TimeoutError and concurrent.futures.TimeoutError should be caught:
from concurrent.futures import TimeoutError as FuturesTimeoutError
except (TimeoutError, FuturesTimeoutError):
future.cancel()
raise TimeoutError()
Impact
- Severity: Critical
- Affected versions: Python 3.9, 3.10
- Symptom: Timeout never triggers properly, task crashes with unhandled exception
Priority
Critical
Description
_execute_with_timeoutincore/engine.pycallsfuture.result(timeout=seconds), which raisesconcurrent.futures.TimeoutErroron expiry. The catch block at lines 134 and 176 catches bareTimeoutError(the builtin).On Python 3.9 and 3.10,
concurrent.futures.TimeoutErroris a separate class that inherits directly fromException, not frombuiltins.TimeoutError. This means the timeout is never caught on those versions.Location
dotflow/core/engine.py— lines 134, 170-178Current Behavior
On Python 3.9/3.10,
concurrent.futures.TimeoutErrorpropagates uncaught, bypasses retry logic, and the task is marked FAILED with a confusing generic error instead of a properTimeoutError.Expected Behavior
Both
builtins.TimeoutErrorandconcurrent.futures.TimeoutErrorshould be caught:Impact
Priority
Critical