-
Notifications
You must be signed in to change notification settings - Fork 6
Fix: Replace stack traces with user-friendly error messages #27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…ly messages
Implements a comprehensive exception handling decorator that catches errors
during command initialization and dependency injection, replacing raw Python
stack traces with clear, actionable error messages.
Changes:
- Add handle_cli_exceptions decorator to catch all exceptions before they
become stack traces
- Provide specific handling for known error types (network, timeout, SSL,
server disconnect errors)
- Generic catch-all handler for unexpected exceptions shows error type and
message without stack trace
- Apply decorator to 11 commands that use dependency injection
- Add 16 comprehensive unit tests covering sync/async functions and all
error types
Key design principles:
- Conservative approach: only apply specific handlers when confident about
error type
- Generic fallback ensures NO stack traces are ever shown to users
- Error messages are clean without redundant advice (original error messages
already contain helpful context)
Before:
$ workato workspace
Traceback (most recent call last):
[30 lines of Python stack trace...]
ValueError: Could not resolve API credentials...
After:
$ workato workspace
❌ ValueError
Could not resolve API credentials. Please check your profile
configuration or run 'workato init' to set up authentication.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The package was renamed from workato_platform to workato_platform_cli in commit e7d7a23, but the .openapi-generator-ignore file wasn't updated. This caused the OpenAPI generator pre-commit hook to overwrite the workato_platform_cli/__init__.py file (which contains the Workato wrapper class) with an empty template on every commit. Fixed by updating the ignore pattern to match the new package name. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds a new handle_cli_exceptions decorator to handle CLI initialization and network errors with user-friendly messages. The decorator is designed to catch errors that occur during dependency injection and CLI setup, such as network failures, SSL errors, and configuration issues.
- Implements the
handle_cli_exceptionsdecorator with support for both sync and async functions - Adds dedicated error handlers for network, timeout, SSL, and generic CLI errors with JSON output support
- Applies the decorator to multiple CLI commands throughout the codebase
Reviewed Changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/workato_platform_cli/cli/utils/exception_handler.py | Adds handle_cli_exceptions decorator and helper functions for handling CLI-level errors |
| tests/unit/utils/test_exception_handler.py | Comprehensive test suite for the new decorator covering sync/async functions, various error types, and JSON output |
| src/workato_platform_cli/cli/commands/*.py | Applies the new decorator to various command functions (workspace, recipes, push, pull, properties, projects, profiles, data_tables, connectors, connections, api_clients) |
| src/.openapi-generator-ignore | Updates ignored path from workato_platform/__init__.py to workato_platform_cli/__init__.py |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
oalami
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good except for the exiting with a non-zero status code and the copilot raised issue on TimeoutError vs asyncio.TimeoutError looks worth implementing for better type safety.
Ensures consistent exception handling across all CLI commands to catch network errors (DNS, SSL, connection failures) and display user-friendly error messages instead of stack traces. Adds the decorator to 19 commands across 9 files: - projects/command.py: list_projects - connections.py: update, get_oauth_url - data_tables.py: create_data_table - api_clients.py: create, create_key, refresh_secret, list_api_keys - api_collections.py: create, list_collections, list_endpoints, enable_endpoint - recipes/command.py: list_recipes, start, update_connection - connectors/command.py: list_connectors - init.py: init - assets.py: export, import_assets 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Previously, all exception handlers returned None, causing the CLI to exit with code 0 even when errors occurred. This broke CI/CD pipelines and shell scripts that rely on exit codes to detect failures. Changes: - Exception decorators now raise SystemExit(1) after handling errors - Helper functions remain pure display logic (format and print errors) - Consistent behavior across both JSON and table output modes - Applies to both @handle_api_exceptions and @handle_cli_exceptions - Uses "from None" to suppress exception chaining for clean error output This ensures commands like: workato projects list && echo "success" || echo "failed" will correctly show "failed" when errors occur. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Updated exception handler tests to expect SystemExit(1) instead of returning None, matching the new exit code behavior implemented in the previous commit. Changes: - Updated all 43 exception handler tests to use pytest.raises(SystemExit) assertions - Modified @handle_cli_exceptions decorator to let click.Abort propagate through instead of catching it, allowing init command tests to work correctly - All 919 tests now pass 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
In Python 3.11+, asyncio.TimeoutError is an alias for the built-in TimeoutError. This change makes the function signature consistent with what's being caught in the exception handlers. This is a cosmetic fix with no functional impact. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Addressed both:
|
oalami
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Summary
Implements a comprehensive exception handling solution that ensures users never see Python stack traces when running CLI commands. The decorator catches all exceptions during command initialization and dependency injection, providing clear, actionable error messages instead.
Scope of Solution
Two-Tier Exception Handling Strategy
Specific Handlers for Well-Known Exceptions
ClientConnectorError,ClientConnectionError)TimeoutError)ServerDisconnectedError)ClientSSLError,ssl.SSLError)Generic Catch-All for Everything Else
Key Design Principles
@injectto catch dependency injection errorsChanges
handle_cli_exceptionsdecorator toexception_handler.pyBefore & After
Before:
After:
Testing
workato initCloses DEVP-424
🤖 Generated with Claude Code