(low) Классификация таймаута LLM по имени класса вместо isinstance (хрупко) #1397

Closed
opened 2026-06-14 18:11:26 +00:00 by bot-backend · 0 comments
Collaborator

Описание

В _call_with_retries тип ошибки определяется строковым сравнением имени класса: e.__class__.__name__ == 'LLMTimeoutError' (строка 247). Работает для текущего напрямую поднимаемого LLMTimeoutError, но молча сломается, если появится подкласс LLMTimeoutError (не пройдёт строковое равенство → будет помечен как 'provider_error' вместо 'timeout') или класс переименуют без обновления литерала.

Корень

LLMTimeoutError не импортирован в client.py (строки 29-36 импортируют из .provider только LLMProvider, LLMProviderError, LLMRateLimitedError, OpenAIProvider, ProviderResponse, ToolCall). Строковое сравнение — обходной путь из-за пропущенного импорта, а не намеренный паттерн (класс экспортируется в provider.__all__ и в __init__.py, то есть доступен).

Evidence

client.py:247:

reason = "timeout" if e.__class__.__name__ == "LLMTimeoutError" else "provider_error"

Suggested fix

Добавить импорт LLMTimeoutError из .provider и заменить на проверку типа: reason = "timeout" if isinstance(e, LLMTimeoutError) else "provider_error" — покроет и будущие подклассы.

Severity-обоснование

low: сейчас бескрылый — единственный raise-сайт (provider.py) поднимает ровно LLMTimeoutError (не подкласс), субклассов в кодовой базе нет, поэтому сравнение работает корректно. Последствие при гипотетическом переименовании/подклассировании — неверный reason в LLMResult.fallback (влияет только на логи/метрики, не на доступность сервиса).


week ревью 1 · multi-agent аудит 2026-06-14 · severity=low · category=error-handling

Затронутые файлы:

  • /Users/anton/Птица/gendesign/backend/app/services/llm/client.py
## Описание В `_call_with_retries` тип ошибки определяется строковым сравнением имени класса: `e.__class__.__name__ == 'LLMTimeoutError'` (строка 247). Работает для текущего напрямую поднимаемого `LLMTimeoutError`, но молча сломается, если появится подкласс `LLMTimeoutError` (не пройдёт строковое равенство → будет помечен как 'provider_error' вместо 'timeout') или класс переименуют без обновления литерала. ## Корень `LLMTimeoutError` не импортирован в `client.py` (строки 29-36 импортируют из `.provider` только `LLMProvider`, `LLMProviderError`, `LLMRateLimitedError`, `OpenAIProvider`, `ProviderResponse`, `ToolCall`). Строковое сравнение — обходной путь из-за пропущенного импорта, а не намеренный паттерн (класс экспортируется в `provider.__all__` и в `__init__.py`, то есть доступен). ## Evidence `client.py:247`: ```python reason = "timeout" if e.__class__.__name__ == "LLMTimeoutError" else "provider_error" ``` ## Suggested fix Добавить импорт `LLMTimeoutError` из `.provider` и заменить на проверку типа: `reason = "timeout" if isinstance(e, LLMTimeoutError) else "provider_error"` — покроет и будущие подклассы. ## Severity-обоснование **low**: сейчас бескрылый — единственный raise-сайт (`provider.py`) поднимает ровно `LLMTimeoutError` (не подкласс), субклассов в кодовой базе нет, поэтому сравнение работает корректно. Последствие при гипотетическом переименовании/подклассировании — неверный `reason` в `LLMResult.fallback` (влияет только на логи/метрики, не на доступность сервиса). --- _week ревью 1 · multi-agent аудит 2026-06-14 · severity=**low** · category=`error-handling`_ Затронутые файлы: - `/Users/anton/Птица/gendesign/backend/app/services/llm/client.py`
bot-backend added the
week ревью 1
label 2026-06-14 18:11:26 +00:00
bot-backend added the
scope/backend
label 2026-06-15 11:01:58 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#1397
No description provided.