fix: client-cancelled GET /v0/servers returns 499 without error log (#1335)
Maps context.Canceled from ListServers to 499 and skips the error-level log on client disconnect. Merged as-is per maintainer decision; known follow-up tracked in #1337 (500-path error-detail leak + WriteHeader claim correction + nits).
This commit is contained in:
parent
04623ed925
commit
ef29673221
3 changed files with 53 additions and 2 deletions
21
internal/api/handlers/v0/list_errors.go
Normal file
21
internal/api/handlers/v0/list_errors.go
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
package v0
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log"
|
||||
|
||||
"github.com/danielgtaylor/huma/v2"
|
||||
)
|
||||
|
||||
// ListServersError maps ListServers failures; client disconnects must not log as 500s.
|
||||
func ListServersError(ctx context.Context, err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if errors.Is(err, context.Canceled) || errors.Is(ctx.Err(), context.Canceled) {
|
||||
return huma.NewError(499, "Client closed request", err)
|
||||
}
|
||||
log.Printf("list servers failed: %v", err)
|
||||
return huma.Error500InternalServerError("Failed to get registry list", err)
|
||||
}
|
||||
31
internal/api/handlers/v0/list_errors_test.go
Normal file
31
internal/api/handlers/v0/list_errors_test.go
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package v0_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/danielgtaylor/huma/v2"
|
||||
v0 "github.com/modelcontextprotocol/registry/internal/api/handlers/v0"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestListServersError_clientCanceled(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
err := v0.ListServersError(ctx, errors.New("error iterating rows: context canceled"))
|
||||
require.Error(t, err)
|
||||
var se huma.StatusError
|
||||
require.True(t, errors.As(err, &se))
|
||||
assert.Equal(t, 499, se.GetStatus())
|
||||
}
|
||||
|
||||
func TestListServersError_realFailure(t *testing.T) {
|
||||
err := v0.ListServersError(context.Background(), errors.New("database unavailable"))
|
||||
require.Error(t, err)
|
||||
var se huma.StatusError
|
||||
require.True(t, errors.As(err, &se))
|
||||
assert.Equal(t, 500, se.GetStatus())
|
||||
}
|
||||
|
|
@ -132,8 +132,7 @@ func RegisterServersEndpoints(api huma.API, pathPrefix string, registry service.
|
|||
// Get paginated results with filtering
|
||||
servers, nextCursor, err := registry.ListServers(ctx, filter, input.Cursor, input.Limit)
|
||||
if err != nil {
|
||||
log.Printf("list servers failed: %v", err)
|
||||
return nil, huma.Error500InternalServerError("Failed to get registry list")
|
||||
return nil, ListServersError(ctx, err)
|
||||
}
|
||||
|
||||
// Convert []*ServerResponse to []ServerResponse
|
||||
|
|
|
|||
Loading…
Reference in a new issue