Add structured error handling with exception hierarchy - #7
Merged
Conversation
Replace raw Python stack traces with user-friendly error messages for all user-facing errors (bad config, provider failures, missing secrets). - Add psi/errors.py with PsiError, ConfigError, ProviderError, and SecretNotFoundError exception classes - Add top-level exception handler in cli.py main() that catches known errors (exit 1) and wraps unexpected errors as bug reports (exit 2) - Catch ValidationError in settings.py load_settings() and translate to ConfigError with per-field details - Replace RuntimeError/ValueError with ProviderError in both providers, PKCS#11 session management, and PIN resolution - Return structured JSON error bodies from the HTTP serve handler - Catch PsiError in shell driver lookup() and route through _fail()
- Catch yaml.YAMLError in load_settings() and raise ConfigError - Catch httpx.ConnectError in Infisical provider lookup() and setup.py for unreachable API errors
jdoss
added a commit
that referenced
this pull request
Apr 8, 2026
The error-handling cleanup in #7 wrapped lookup-path httpx errors but missed psi/providers/infisical/auth.py:_parse_token_response. When Infisical returned 502 during its own boot, the raw HTTPStatusError escaped through psi setup's retry loop and surfaced as the CLI bug-report panel instead of a clean error message. Wrap the auth response in ProviderError with the status code and a body snippet, preserving __cause__ so setup._is_retryable still unwraps and retries 502/503/404. Add httpx.HTTPError as a last-resort catch in cli.main() so any future stray httpx exception lands as "Network error" instead of the bug panel. Tests: unit coverage for _parse_token_response wrapping; setup retry tests covering a 502 wrapped as ProviderError retrying through all attempts and a 401 wrapped as ProviderError failing immediately; CLI tests for the httpx fallback branch.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
psi/errors.pywithPsiError,ConfigError,ProviderError, andSecretNotFoundErrorcli.py main(): user errors exit 1 with message, bugs exit 2 with tracebackValidationErrorinload_settings(), translate toConfigErrorwith per-field detailsRuntimeError/ValueErrorwithProviderErrorin both providers, PKCS#11, and PIN resolution{"error": "...", "detail": "..."}) from the HTTP serve handlerlookup()catchesPsiErrorand routes through_fail()for plain-text stderr outputTest plan
ruff checkandruff format --checkpassty checkpassespsi setupwith missing config shows friendly error, no tracebackpsi setupwith invalid YAML shows friendly error