Labels: bug, runtime
Severity: S1.
| Finding (path:line) |
Issue |
runtime/orchestrator.py:301 |
Operator-precedence bug: route.selected_module or "" if route else "" parses as selected_module or ("" if route else ""), accessing .selected_module before the None guard. When routing throws (route is None), _finalize_run raises AttributeError, loses the run record, and masks the original error |
platform/exceptions.py:31-78 + api/errors/handlers.py:138 |
AuthenticationError/RateLimitError/NotFoundError/ValidationError/UpstreamError/TimeoutError lack an http_status ClassVar -> the handler returns 500 for all; clients cannot distinguish 401/404/422/429/502/504 and retry logic breaks |
runtime/orchestrator.py:279-301 |
_finalize_run catches only SQLAlchemyError; a non-DB error inside (the precedence bug, model_dump_json on a bad route) propagates and replaces the original exception; the raise at :195 never runs |
platform/exceptions.py:74 |
Custom TimeoutError(AILAError) shadows the builtin; asyncio.wait_for raises the builtin -> except TimeoutError in one context misses the other |
runtime/orchestrator.py:88 vs builder.py:180 |
init_db called twice on cold start (platform-only then with schema_registry) and passes PlatformSettings where ApplicationSettings is expected -> redundant round-trip + type confusion |
runtime/orchestrator.py:86-105 |
_ensure_initialized() has no instance lock -> two concurrent handle() calls on a fresh AILAPlatform build two runtimes/routers, second overwrites first (only the worker path has a lock) |
platform/rate_limiter.py:82-84 |
Tokens driven arbitrarily negative under concurrent burst -> O(N) cumulative sleep for the last caller (~75s at 100 concurrent), no max-queue-depth / backpressure |
runtime/orchestrator.py:34 |
asyncio.Lock() created at import time before any loop -> DeprecationWarning; possible loop-mismatch RuntimeError under uvloop |
Acceptance: the None guard precedes attribute access; every domain error declares its HTTP status; _finalize_run preserves the original exception; the custom timeout error renamed; single idempotent init behind an instance lock; rate limiter clamps debt with backpressure; the lock created lazily inside the loop.
Labels: bug, runtime
Severity: S1.
runtime/orchestrator.py:301route.selected_module or "" if route else ""parses asselected_module or ("" if route else ""), accessing.selected_modulebefore the None guard. When routing throws (route is None),_finalize_runraisesAttributeError, loses the run record, and masks the original errorplatform/exceptions.py:31-78+api/errors/handlers.py:138AuthenticationError/RateLimitError/NotFoundError/ValidationError/UpstreamError/TimeoutErrorlack anhttp_statusClassVar -> the handler returns 500 for all; clients cannot distinguish 401/404/422/429/502/504 and retry logic breaksruntime/orchestrator.py:279-301_finalize_runcatches onlySQLAlchemyError; a non-DB error inside (the precedence bug,model_dump_jsonon a bad route) propagates and replaces the original exception; theraiseat :195 never runsplatform/exceptions.py:74TimeoutError(AILAError)shadows the builtin;asyncio.wait_forraises the builtin ->except TimeoutErrorin one context misses the otherruntime/orchestrator.py:88vsbuilder.py:180init_dbcalled twice on cold start (platform-only then with schema_registry) and passesPlatformSettingswhereApplicationSettingsis expected -> redundant round-trip + type confusionruntime/orchestrator.py:86-105_ensure_initialized()has no instance lock -> two concurrenthandle()calls on a freshAILAPlatformbuild two runtimes/routers, second overwrites first (only the worker path has a lock)platform/rate_limiter.py:82-84runtime/orchestrator.py:34asyncio.Lock()created at import time before any loop -> DeprecationWarning; possible loop-mismatch RuntimeError under uvloopAcceptance: the None guard precedes attribute access; every domain error declares its HTTP status;
_finalize_runpreserves the original exception; the custom timeout error renamed; single idempotent init behind an instance lock; rate limiter clamps debt with backpressure; the lock created lazily inside the loop.