fix: return 503 instead of 500 when upstream registry is unavailable#4352
fix: return 503 instead of 500 when upstream registry is unavailable#4352
Conversation
When the configured registry API URL is wrong or the upstream registry returns a non-auth error (404, timeout, connection refused), the GET endpoints now return HTTP 503 with a structured JSON response containing code "registry_unavailable" and the original error message, instead of a generic 500 "Failed to get registry". This follows the same pattern as the existing "registry_auth_required" 503 response, allowing clients to distinguish between auth issues and upstream availability issues. Fixes #4351 Made-with: Cursor
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4352 +/- ##
==========================================
+ Coverage 68.84% 68.96% +0.12%
==========================================
Files 479 480 +1
Lines 48505 48547 +42
==========================================
+ Hits 33392 33481 +89
+ Misses 12365 12284 -81
- Partials 2748 2782 +34 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…tter Address golangci-lint revive and gci formatting issues: - Rename RegistryUnavailableError → UnavailableError (registry.RegistryUnavailableError stutters) - Fix struct field alignment formatting (gci) Made-with: Cursor
|
@claude succinct review |
|
Claude finished @peppescg's task in 57s —— View job Code ReviewOverall: Clean, well-structured implementation. A few minor issues worth addressing. Issues1. Misleading struct reuse (
2. Duplicate error types for the same concept (
3. Missing Swagger The three GET handlers ( // @Failure 503 {object} registryAuthErrorResponse "Registry unavailable"4. Raw upstream error exposed in response body
Minor observationThe Summary: Functionally correct. The main actionable items are (1) rename |
The struct is now used for both registry_auth_required and registry_unavailable 503 responses, so the name should be generic. Made-with: Cursor

Summary
When the configured registry API URL is wrong or the upstream registry returns a non-auth error (e.g. 404, timeout, connection refused), the GET registry endpoints returned a generic 500 Internal Server Error with plain text
"Failed to get registry". This made it impossible for clients (like ToolHive Studio) to distinguish a misconfigured URL from a real server bug.This PR introduces a
RegistryUnavailableErrortype and returns 503 Service Unavailable with a structured JSON response containing"code": "registry_unavailable"and the original upstream error message, following the same pattern as the existingregistry_auth_required503 response.Fixes #4351
Type of change
Test plan
task test)task test-e2e)task lint-fix)Manual testing with
curl:/api/v1beta/registry→ 503 with{"code":"registry_unavailable","message":"upstream registry at ... is unavailable: registry API returned status 404 ..."}/registry,/registry/default,/registry/default/servers) return the same 503 JSONregistry_auth_required(correct behavior)Changes
pkg/registry/errors.goRegistryUnavailableErrortype withError(),Unwrap()pkg/registry/errors_test.gopkg/registry/provider_api.goRegistryUnavailableErrorinGetRegistry()andNewAPIRegistryProviderpkg/api/v1/registry.gowriteRegistryUnavailableError()helper; check forRegistryUnavailableErroringetCurrentProvider,listRegistries,getRegistry,listServerspkg/api/v1/registry_test.goDoes this introduce a user-facing change?
Yes. Registry GET endpoints now return HTTP 503 with a structured JSON body
{"code": "registry_unavailable", "message": "..."}instead of HTTP 500 with plain text when the upstream registry is unreachable or misconfigured. Clients can use thecodefield to distinguish this fromregistry_auth_required.Special notes for reviewers
The
RegistryUnavailableErrorfollows the same pattern as the existingconnectivityErrortype used in the PUT handler. The 503 JSON response reuses theregistryAuthErrorResponsestruct since it has the same shape (code+message).