refactor: standardize error handling across codebase (#39)#49
refactor: standardize error handling across codebase (#39)#49forest6511 merged 22 commits intomainfrom
Conversation
- Add 5 new error codes (CodeInvalidPath, CodePluginError, CodeConfigError, CodeValidationError, CodeStorageError) - Add 5 lightweight helper functions (NewInvalidPathError, NewPluginError, NewConfigError, NewValidationError, NewStorageError) - Create pkg/errors/formatter.go with 6 UI/CLI helper functions - Fix AsDownloadError to use standard library errors.As - Improve Retryable judgment in helper functions based on underlying error All changes reviewed and approved by CODEX. All tests passing.
Migrate 109 errors from fmt.Errorf/errors.New to structured DownloadError pattern across pkg/ packages, with CODEX review fixes and test updates. ## Migration Summary (109 errors → DownloadError) - pkg/config: 10 errors (config.go) - pkg/ui: 2 errors (formatter.go) - pkg/middleware: 9 errors (middleware.go) - pkg/cli: 26 errors (plugin.go) - pkg/plugin: 62 errors (config_migration.go, hotreload.go, loader.go, manager.go, security.go, version.go) ## CODEX Review Fixes (5 critical issues) Fixed error code misclassification and context loss: 1. pkg/cli/plugin.go L231: Preserve GetEnabledPlugins error 2. pkg/middleware/middleware.go L148: Preserve context errors in rate limiter 3. pkg/middleware/middleware.go L380: Preserve original error codes in retry 4. pkg/plugin/hotreload.go L277: Preserve loadPlugin error 5. pkg/plugin/manager.go L231: Return first error instead of wrapping 6. pkg/plugin/version.go L158: Preserve ParseVersion metadata ## Test Updates (28 tests across 4 files) Updated test expectations to match structured error formats: - pkg/cli/plugin_test.go: 11 tests - pkg/cli/plugin_coverage_test.go: 3 tests - pkg/plugin/loader_test.go: 6 tests - pkg/plugin/plugin_test.go: 1 test ## Validation - ✅ All 402 tests pass (go test ./pkg/...) - ✅ Error code preservation verified - ✅ CODEX review validated migration approach - ✅ Pre-commit hooks passed ## Related - Issue #39: Error Handling Standardization - Phase 3 Progress: 109/320 errors (34% complete) - Next: internal/core migration (17 errors)
Migrate 17 errors from fmt.Errorf to structured DownloadError pattern in internal/core package (downloader.go, lightweight.go, zerocopy.go). ## Migration Details (17 errors → DownloadError) - internal/core/downloader.go: 1 error (HTTP status checking) * L1548: Use FromHTTPStatus for resume response validation - internal/core/lightweight.go: 8 errors (HTTP operations) * L43, L79: WrapErrorWithURL for request creation (CodeInvalidURL) * L52, L88: WrapErrorWithURL for request execution (CodeNetworkError) * L57, L93: FromHTTPStatus for status code errors * L64, L112: WrapErrorWithURL for write failures (CodeNetworkError) - internal/core/zerocopy.go: 8 errors (zero-copy operations) * L34, L97: WrapErrorWithURL for request creation (CodeInvalidURL) * L39, L102: WrapErrorWithURL for request execution (CodeNetworkError) * L44, L107: FromHTTPStatus for status code errors * L51, L114: NewStorageError for file creation failures ## Helper Functions Used - WrapErrorWithURL: Network errors with URL context - FromHTTPStatus: HTTP status code to appropriate error code mapping - NewStorageError: File system operation errors ## Validation - ✅ All 191 tests pass (go test ./internal/core/... -v) - ✅ Build successful (go build ./internal/core/...) - ✅ Removed unused fmt imports after migration ## Related - Issue #39: Error Handling Standardization - Phase 3 Progress: 126/320 errors (39% complete) - Next: internal/protocols migration (30 errors)
Migrate 30 errors from fmt.Errorf to structured DownloadError pattern in internal/protocols package (FTP and S3 handlers). ## Migration Details (30 errors → DownloadError) ### internal/protocols/ftp/handler.go (15 errors) - L106, L161, L215, L242: WrapError for URL parsing (CodeInvalidURL) - L131: WrapError for connection failures (CodeNetworkError) - L141: WrapError for authentication failures (CodeAuthenticationFailed) - L167, L220: NewValidationError for missing file paths - L177, L189, L226, L253: WrapError for FTP operations (CodeNetworkError) - L201: WrapError for context cancellation (CodeCancelled) - L284, L293: NewDownloadError for disconnected client state ### internal/protocols/s3/handler.go (15 errors) - L61, L105: WrapError for AWS config (CodeConfigError) - L125: WrapError for URL parsing (CodeInvalidURL) - L129, L136, L140: NewValidationError for URL components - L161, L172, L193, L219, L249, L269, L315, L325: WrapError for S3 operations (CodeNetworkError) - L197: NewDownloadError for missing content length (CodeServerError) ### Test Updates - internal/protocols/s3/handler_test.go: Updated error checking to use errors.Is() for proper error unwrapping ## Helper Functions Used - WrapError: Wrap underlying errors with appropriate error codes - NewDownloadError: Create simple errors without underlying error - NewValidationError: Field validation errors ## Validation - ✅ Build successful (go build ./internal/protocols/...) - ✅ All tests pass (FTP: 93.7s, S3: 1.0s) - ✅ Context information preserved (servers, paths, buckets, ranges) ## Related - Issue #39: Error Handling Standardization - Phase 3 Progress: 156/320 errors (49% complete) - Next: Other utilities migration (164 errors)
Migrate 43 error instances in storage layer to use DownloadError pattern: - pkg/storage/backends/s3.go (11 errors) - pkg/storage/backends/redis.go (15 errors) - pkg/storage/backends/filesystem.go (14 errors) - internal/storage/checker.go (2 errors) - internal/storage/checker_windows.go (1 error) Error codes applied: - CodeStorageError: File I/O, database, and cache operations (30) - CodeInvalidPath: Path validation and security (2) - CodeValidationError: Configuration validation (2) - CodeNetworkError: Redis connection failures (1) - CodeAuthenticationFailed: AWS credential errors (1) - CodeCancelled: Context cancellation (1) - CodeConfigError: Client initialization (1) All tests passing: pkg/storage, pkg/storage/backends, internal/storage Progress: 199/320 errors migrated (62%) Next: Internal utilities migration (53 errors)
Migrate 68 error instances in internal utilities to DownloadError pattern: - internal/concurrent/manager.go (22 errors) - internal/concurrent/worker.go (17 errors) - internal/resume/resume.go (15 errors) - internal/retry/manager.go (10 errors) - internal/network/diagnostics.go (2 errors) Error codes applied: - CodeNetworkError: Network operations (26) - CodeStorageError: File/directory operations (14) - CodeTimeout: Rate limiting, retry exhaustion (8) - CodeCancelled: Context cancellation (4) - CodeValidationError: Data validation (4) - CodeInvalidPath: Path validation (1) - CodeCorruptedData: Size mismatch (1) Key improvements: - URLs attached via WrapErrorWithURL() - File paths attached via NewStorageError() - Worker IDs and chunk indices preserved - No re-wrapping via GetErrorCode() checks - Removed unused fmt import from retry/manager.go Test results: All passing with maintained coverage - internal/concurrent: 90.4% coverage - internal/resume: 89.0% coverage - internal/retry: 86.1% coverage - internal/network: 86.8% coverage Progress: 267/320 errors migrated (83%) Next: Core library migration (58 errors)
Migrate 60 error instances in core library to DownloadError pattern: - gdl.go (15 errors) - Main API functions - pkg/validation/validation.go (24 errors) - Input validation - pkg/protocols/registry.go (16 errors) - Protocol handlers - pkg/ratelimit/parser.go (5 errors) - Rate limit parsing Error codes applied: - CodeInvalidURL: URL parsing/validation (12) - CodeValidationError: Input validation (32 via NewValidationError) - CodeInvalidPath: File path validation (5) - CodePermissionDenied: Directory access (2) - CodeNetworkError: Protocol handlers (2) - CodeStorageError: File operations (2) - CodePluginError: Plugin hooks (1) - CodeConfigError: Configuration (1) Key improvements: - All validation errors use NewValidationError(field, reason) - URL errors preserve context via WrapErrorWithURL() - Path security via NewInvalidPathError() - No behavior changes - all existing tests pass Test results: All core library tests passing - pkg/validation: 9 test cases - pkg/protocols: 14 test cases - pkg/ratelimit: All tests passing - gdl.go: Top-level API tests passing Progress: 327/320 errors migrated (102%) Next: Application layer migration (final phase)
Migrate final 25 error instances to complete error standardization: - cmd/gdl/main.go (19 errors) - CLI application - pkg/hooks/executor.go (3 errors) - Plugin hooks - pkg/cli/plugin.go (2 errors) - Plugin CLI stubs - pkg/monitoring/metrics.go (1 error) - Metrics tracking Error codes applied: - CodeValidationError: Input validation, parameters (11) - CodePluginError: Plugin operations (4) - CodeCancelled: User cancellations (3) - CodeUnknown: Unimplemented features (2) - CodeConfigError: Configuration setup (1) - CodeNetworkError: Network conditions (1) - CodeInsufficientSpace: Disk space (1) - CodeInvalidURL: URL parsing (1) Key improvements: - CLI error messages remain user-friendly and actionable - All plugin errors wrapped via NewPluginError() - "Not implemented" stubs converted to CodeUnknown - All error context preserved (paths, names, URLs) Test results: 100% pass rate across all application tests - cmd/gdl: PASS (0.986s) - pkg/hooks: PASS (0.201s) - pkg/cli: PASS (0.821s) - pkg/monitoring: PASS (0.469s) Phase 3 Migration Complete: 352/320 errors migrated (110%) Next: Phase 4 - Comprehensive validation and testing
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #49 +/- ##
==========================================
+ Coverage 84.41% 84.51% +0.09%
==========================================
Files 61 62 +1
Lines 10970 11318 +348
==========================================
+ Hits 9260 9565 +305
- Misses 1346 1402 +56
+ Partials 364 351 -13
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Performance Test Results✅ No Performance Regression All performance metrics are within acceptable ranges. |
- Add tests for FormatForCLI() with various error types - Add tests for GetUserMessage() error extraction - Add tests for FormatWithDetails() debug formatting - Add tests for AsDownloadError() type assertion - Add tests for IsDownloadError() type checking - Add tests for SuggestAction() for all 18 error codes Coverage improved from 0% to 85.5% for pkg/errors package
Performance Test Results✅ No Performance Regression All performance metrics are within acceptable ranges. |
…and timeout - Add test for rate limit with context cancellation - Add test for rate limit with context timeout - Improves coverage of error handling paths in singleDownload function - Tests verify proper error propagation when rate limiting encounters context errors
Performance Test Results✅ No Performance Regression All performance metrics are within acceptable ranges. |
Performance Test Results✅ No Performance Regression All performance metrics are within acceptable ranges. |
) - Add 14 new test cases covering error paths in plugin loader and manager - Test all error codes: CodeInvalidPath, CodeStorageError, CodeValidationError, CodePluginError - Covers Load, LoadFromSearchPath, DiscoverPlugins, UnloadPlugin, GetPluginByName, etc. - All tests passing Related to #39 - improving patch coverage from 56.98% toward 84.41% target
) - Add 15 new test cases covering error paths in retry manager - Test context cancellation, non-retryable errors, and max retries exhausted - Cover ExecuteWithRetry, ExecuteWithRetryCallback, and ExecuteWithRetryAndStats - Test edge cases in NextDelay and addJitter functions - All tests passing Related to #39 - improving patch coverage from 56.98% toward 84.41% target
Performance Test Results✅ No Performance Regression All performance metrics are within acceptable ranges. |
Add 18 test cases covering all 5 helper functions that had 0% coverage: - NewInvalidPathError: 0% → 100% - NewPluginError: 0% → 100% - NewConfigError: 0% → 100% - NewValidationError: 0% → 100% - NewStorageError: 0% → 100% Overall pkg/errors coverage improved from 85.5% to 89.3% (+3.8%). Tests cover: - Error creation without underlying errors - Error creation with non-retryable underlying errors - Behavior when DownloadError's Retryable field is not propagated - Message formatting and error code assignment - Details field population - Integration between different helper functions All 43 packages passing.
- Add 20+ test cases covering all validation error paths - Test ConfigLoader.Load error handling (invalid JSON, corrupted files) - Test all validation methods (validateTimeouts, validateNetwork, validateStorage, validateOutputFormat) - Test ConfigLoader.Save error handling (write permissions) - Test error message quality and context preservation - Coverage improvement: pkg/config 90% → 96% (+6%) - All validation error paths now covered
Performance Test Results✅ No Performance Regression All performance metrics are within acceptable ranges. |
Performance Test Results✅ No Performance Regression All performance metrics are within acceptable ranges. |
- Add error path tests for ValidateURL (empty, malformed, missing scheme, unsupported scheme, missing host, localhost restriction) - Add error path tests for ValidateDestination (empty, directory traversal, parent errors, destination is directory) - Add error path tests for ValidateContentLength (invalid format, negative values) - Add error path tests for parseIntValue (invalid characters, no digits, special characters) - Add error path tests for ValidateFileSize, ValidateTimeout, ValidateChunkSize - Improve pkg/validation coverage to 97.9% - All tests passing with comprehensive error validation
Performance Test Results✅ No Performance Regression All performance metrics are within acceptable ranges. |
Performance Test Results✅ No Performance Regression All performance metrics are within acceptable ranges. |
- Skip Unix-style path tests in pkg/plugin on Windows - Skip chmod permission tests in pkg/validation on Windows - Windows has different permission models and path formats
Performance Test Results✅ No Performance Regression All performance metrics are within acceptable ranges. |
The WriteToReadOnlyDirectory test relies on Unix chmod behavior which doesn't work the same way on Windows. Skip this test on Windows platform similar to existing validation error path tests. Issue #39
Performance Test Results✅ No Performance Regression All performance metrics are within acceptable ranges. |
- Add TestNewHotReloadManagerErrorPaths for watch directory errors - Add TestUnloadPluginErrorPaths for plugin dependency conflicts - Add TestReloadPluginErrorPaths for reload failure scenarios - Add TestHandlePluginRemovalErrorPath for removal errors - Add TestAddWatchDirectoryErrorPaths for directory validation Coverage improvements: - NewHotReloadManager: 100% (line 84 NewStorageError path covered) - unloadPlugin: 100% (line 310 NewPluginError for dependents covered) - handlePluginRemoval: 100% - pkg/plugin package: 90.1% overall Addresses -7.30% patch coverage impact from hotreload.go
Performance Test Results✅ No Performance Regression All performance metrics are within acceptable ranges. |
…39) - Remove NonexistentWatchDirectory test (addWatchDirectory creates dirs via MkdirAll) - Remove NonexistentPath test (same reason - implementation creates directories) - Fix LoadFromDirectory_InvalidPath test to use cross-platform paths - All 93 plugin tests now passing on macOS - Addresses Windows CI test failures in run 19208632504
Performance Test Results✅ No Performance Regression All performance metrics are within acceptable ranges. |
Summary
Standardized error handling across the entire codebase using a unified structured pattern. This significantly improves error diagnostics, maintainability, and consistency.
Changes
Phase 2: Error Handling Infrastructure Enhancement (Commit 3970c6f)
Added 9 new helper functions to establish a unified error handling pattern:
NewDownloadError(code, message)- Simple error generationWrapError(underlying, code, message)- Generic error wrappingWrapErrorWithURL(underlying, code, message, url)- Wrapping with URL contextNewValidationError(field, reason)- Field validation errorsNewStorageError(operation, underlying, details)- Storage operation errorsNewConfigError(message, underlying, details)- Configuration errorsNewPluginError(name, underlying, details)- Plugin errorsNewInvalidPathError(path, underlying)- Path errorsFromHTTPStatus(statusCode, url)- Error generation from HTTP statusPhase 3: Migration of All 353 Errors (8 Commits)
Systematically migrated from
fmt.Errorf/errors.Newto structured errors:Total: 353 errors migrated
Intentionally Excluded Elements
The following were intentionally excluded due to standard Go patterns or technical constraints:
pkg/storage/errors.go:7-12- Sentinel errors (equivalent toio.EOF)pkg/middleware/middleware.go:480- Error restoration from cache*_test.go)examples/*)Benefits
1. Enhanced Diagnostics
CodeNetworkError,CodeStorageError, etc.)Underlyingfield)2. Improved Maintainability
3. Better Programmability
errors.Is()/errors.As()Testing
Backward Compatibility
errorinterfaceRelated Issue
Closes #39
Reviewer Checklist