Skip to content

Conversation

@jerm-dro
Copy link
Contributor

@jerm-dro jerm-dro commented Jan 7, 2026

Summary

This PR implements standardized error handling for the thv API as described in #3106. Previously, error-to-HTTP-status-code mapping was duplicated and inconsistent across API handlers. This change introduces a centralized error handling mechanism using an ErrorHandler decorator.

Large PR Justification

Readers will find these changes are pretty simple, so it made sense to do the entire refactor in one PR. Most of the changes come from rewriting existing errors to follow the new pattern.

Changes

New Error Package (pkg/errors)

  • Added WithCode(error, int) to wrap errors with HTTP status codes
  • Added Code(error) to extract HTTP status codes from errors (defaults to 500)
  • Added New(msg, code) to create new errors with codes
  • Added HasCode(error) to check if an error has an associated code
  • Supports Go's standard errors.Is() and errors.As() through proper Unwrap() implementation

New API Error Handler (pkg/api/errors)

  • Added ErrorHandler decorator that wraps handlers returning error
  • Automatically converts errors to appropriate HTTP responses based on their codes
  • Returns generic "Internal Server Error" for 5xx errors (avoids leaking sensitive details)
  • Returns specific error messages for 4xx errors

Updated Sentinel Errors

Wrapped existing sentinel errors with appropriate HTTP status codes:

  • groups.ErrGroupAlreadyExists → 409 Conflict
  • groups.ErrGroupNotFound → 404 Not Found
  • groups.ErrInvalidGroupName → 400 Bad Request
  • runtime.ErrWorkloadNotFound → 404 Not Found
  • workloads/types.ErrInvalidWorkloadName → 400 Bad Request
  • workloads/types/errors.ErrRunConfigNotFound → 404 Not Found
  • retriever.ErrBadProtocolScheme → 400 Bad Request
  • retriever.ErrImageNotFound → 404 Not Found
  • retriever.ErrInvalidRunConfig → 400 Bad Request
  • secrets.ErrUnknownManagerType → 400 Bad Request
  • secrets.ErrSecretsNotSetup → 404 Not Found
  • secrets.ErrKeyringNotAvailable → 400 Bad Request
  • session.ErrSessionNotFound → 404 Not Found

Refactored API Handlers

Updated all API handlers in pkg/api/v1 to:

  • Return error instead of writing http.Error directly
  • Use ErrorHandler decorator in router setup
  • Rely on error codes for HTTP status mapping instead of errors.Is checks

Affected files:

  • pkg/api/v1/workloads.go
  • pkg/api/v1/groups.go
  • pkg/api/v1/clients.go
  • pkg/api/v1/secrets.go

Documentation

  • Updated docs/error-handling.md to reflect the new error handling strategy

Testing

  • Added unit tests for pkg/errors package covering WithCode, Code, HasCode, New, and error unwrapping
  • Added unit tests for ErrorHandler decorator verifying correct status codes and response body content
  • Updated existing API tests to work with the new handler signatures

Closes #3106

@github-actions github-actions bot added the size/XL Extra large PR: 1000+ lines changed label Jan 7, 2026
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Large PR Detected

This PR exceeds 1000 lines of changes and requires justification before it can be reviewed.

How to unblock this PR:

Add a section to your PR description with the following format:

## Large PR Justification

[Explain why this PR must be large, such as:]
- Generated code that cannot be split
- Large refactoring that must be atomic
- Multiple related changes that would break if separated
- Migration or data transformation

Alternative:

Consider splitting this PR into smaller, focused changes (< 1000 lines each) for easier review and reduced risk.

See our Contributing Guidelines for more details.


This review will be automatically dismissed once you add the justification section.

@codecov
Copy link

codecov bot commented Jan 7, 2026

Codecov Report

❌ Patch coverage is 33.87978% with 242 lines in your changes missing coverage. Please review.
✅ Project coverage is 63.93%. Comparing base (7a16b10) to head (dc3e75c).
⚠️ Report is 10 commits behind head on main.

Files with missing lines Patch % Lines
pkg/api/v1/workloads.go 18.58% 92 Missing ⚠️
pkg/api/v1/clients.go 0.00% 71 Missing ⚠️
pkg/api/v1/secrets.go 41.50% 62 Missing ⚠️
pkg/api/v1/groups.go 62.22% 16 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3218      +/-   ##
==========================================
+ Coverage   63.65%   63.93%   +0.28%     
==========================================
  Files         361      363       +2     
  Lines       35449    35367      -82     
==========================================
+ Hits        22566    22613      +47     
+ Misses      11072    10946     -126     
+ Partials     1811     1808       -3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jan 7, 2026
@github-actions github-actions bot dismissed their stale review January 7, 2026 20:14

Large PR justification has been provided. Thank you!

@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

✅ Large PR justification has been provided. The size review has been dismissed and this PR can now proceed with normal review.

Copy link
Contributor

Copilot AI left a 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 implements centralized error handling for the API layer, replacing scattered http.Error() calls with a standardized approach using HTTP status code annotations on errors.

  • Introduces pkg/errors package with WithCode(), Code(), and New() functions to attach HTTP status codes to errors
  • Adds pkg/api/errors.ErrorHandler decorator that converts errors to HTTP responses, hiding 5xx error details while exposing 4xx messages
  • Refactors 13 sentinel errors across the codebase to include HTTP status codes (404, 400, 409, 503, etc.)
  • Updates all API handlers in v1 package to return errors instead of writing HTTP responses directly

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pkg/errors/errors.go New error package providing CodedError type and utilities for attaching/extracting HTTP status codes
pkg/errors/errors_test.go Comprehensive unit tests for error wrapping, unwrapping, and code extraction
pkg/api/errors/handler.go ErrorHandler decorator that converts returned errors to HTTP responses based on status codes
pkg/api/errors/handler_test.go Unit tests verifying correct HTTP status codes and response bodies for various error scenarios
pkg/workloads/types/validate.go Updates ErrInvalidWorkloadName to include 400 status code
pkg/workloads/types/errors/errors.go Updates ErrRunConfigNotFound to include 404 status code
pkg/transport/session/errors.go Updates 5 session-related errors to include appropriate status codes (404, 409, 400, 503)
pkg/secrets/factory.go Updates 3 secrets errors to include status codes (400, 404)
pkg/runner/retriever/retriever.go Updates 3 retriever errors to include status codes (400, 404)
pkg/groups/errors.go Updates 3 group errors to include status codes (409, 404, 400)
pkg/container/runtime/types.go Updates ErrWorkloadNotFound to include 404 status code
pkg/api/v1/workloads.go Refactors 14 handler methods to return errors, removes manual http.Error calls, applies ErrorHandler decorator
pkg/api/v1/workloads_test.go Updates test assertions for lowercase error messages and wraps handlers with ErrorHandler
pkg/api/v1/secrets.go Refactors 5 handler methods to return errors, removes manual http.Error calls, applies ErrorHandler decorator
pkg/api/v1/secrets_test.go Updates test assertions for lowercase error messages and wraps handlers with ErrorHandler
pkg/api/v1/groups.go Refactors 4 handler methods to return errors, removes manual http.Error calls, applies ErrorHandler decorator
pkg/api/v1/groups_test.go Updates test assertions for lowercase error messages and wraps handlers with ErrorHandler
pkg/api/v1/clients.go Refactors 6 handler methods to return errors, renames internal helper method, applies ErrorHandler decorator
docs/error-handling.md Documents new error handling pattern with examples of WithCode, Code, and ErrorHandler usage

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jan 7, 2026
@jerm-dro jerm-dro requested review from dmjb and eleftherias January 7, 2026 20:32
@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jan 8, 2026
Copy link
Member

@eleftherias eleftherias left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great change!
I noted a couple more places where the code needs to be updated.

@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jan 9, 2026
Signed-off-by: Jeremy Drouillard <jeremy@stacklok.com>
Signed-off-by: Jeremy Drouillard <jeremy@stacklok.com>
Signed-off-by: Jeremy Drouillard <jeremy@stacklok.com>
@jerm-dro jerm-dro force-pushed the jerm/2026-01-07-api-error-handler branch from 39bae64 to bf63c03 Compare January 9, 2026 21:12
@jerm-dro jerm-dro requested a review from eleftherias January 9, 2026 21:12
@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jan 9, 2026
Signed-off-by: Jeremy Drouillard <jeremy@stacklok.com>
@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jan 9, 2026
@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jan 12, 2026
@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jan 13, 2026
@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jan 13, 2026
@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Jan 13, 2026
Copy link
Member

@eleftherias eleftherias left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a CodeQL warning, but I believe it's unrelated to you changes and already documented with the comment // #nosec G304 - filePath is controlled by getFilePath which ensures it's within our designated directory

@jerm-dro jerm-dro merged commit 8aeb567 into main Jan 14, 2026
32 of 33 checks passed
@jerm-dro jerm-dro deleted the jerm/2026-01-07-api-error-handler branch January 14, 2026 15:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/XL Extra large PR: 1000+ lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Standardize Error Handling in thv API

3 participants