Skip to content

refactor(llm): chain exceptions in client error handlers (ruff B904)#145

Merged
CGFixIT merged 1 commit into
mainfrom
claude/cyclaw-optimization-review-u3kgru-llm-exc-chain
Jun 21, 2026
Merged

refactor(llm): chain exceptions in client error handlers (ruff B904)#145
CGFixIT merged 1 commit into
mainfrom
claude/cyclaw-optimization-review-u3kgru-llm-exc-chain

Conversation

@CGFixIT

@CGFixIT CGFixIT commented Jun 21, 2026

Copy link
Copy Markdown
Owner

Summary

LocalLLMClient.generate and GrokClient.generate re-raise LLMServiceError / GrokServiceError from inside their except blocks without from, discarding the original exception's context (__cause__). The project's own ruff config selects the B rule family (pyproject.toml[tool.ruff.lint] select = [..., "B", ...]), so these are six B904 (raise-without-from-inside-except) violations.

except httpx.HTTPStatusError as e:
    raise LLMServiceError(...)          # ← original HTTP error lost
except httpx.TimeoutException:
    raise LLMServiceError("... timeout") # ← no `as e`, no chain
except Exception as e:
    raise LLMServiceError(...)          # ← `e` captured but not chained

Why it matters

The wrappers flatten every failure into a generic message. When something goes wrong talking to LM Studio or xAI (TLS error, connection reset, malformed JSON), the underlying httpx exception — the part that actually tells you what broke — is thrown away. Chaining preserves it as __cause__, so the real cause shows up in tracebacks and debugging:

GrokServiceError: Grok error: ...
The above exception was the direct cause of the following exception:
httpx.ConnectError: [Errno 111] Connection refused

The change

Add from e to all six handlers and bind the two TimeoutException blocks with as e. Behaviour-preserving: exception types, messages, and details are unchanged, so any caller catching LLMServiceError / GrokServiceError is unaffected — only __cause__ is now populated.

Verification

ruff check llm/client.py --select B904   →  0 findings (was 6)
python -c "import ast; ast.parse(open('llm/client.py').read())"  →  parses OK

🤖 Generated with Claude Code

https://claude.ai/code/session_01LvLWMML8cpBq2q81kL1ByJ


Generated by Claude Code

LocalLLMClient.generate and GrokClient.generate re-raise LLMServiceError /
GrokServiceError from inside their except blocks without 'from', discarding the
original exception context. The project's own ruff config selects the 'B' rules,
so these are six B904 (raise-without-from-inside-except) violations.

Add 'from e' to all six handlers (and bind the two TimeoutException blocks with
'as e') so the underlying httpx error is preserved as __cause__. This keeps the
real network/HTTP failure visible in tracebacks and audit diagnostics instead of
masking it behind a generic wrapper. Exception types, messages, and details are
unchanged, so callers that catch these errors are unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LvLWMML8cpBq2q81kL1ByJ
@CGFixIT CGFixIT marked this pull request as ready for review June 21, 2026 02:27
@CGFixIT CGFixIT merged commit d6cbd38 into main Jun 21, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants