Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 21 additions & 13 deletions libs/testproxy/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package testproxy

import (
"bytes"
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
Expand Down Expand Up @@ -129,22 +128,31 @@ func (s *ProxyServer) proxyToCloud(w http.ResponseWriter, r *http.Request) {

var encodedResponse *testserver.EncodedResponse

// API errors from the SDK are expected to be of the type [apierr.APIError]. If we
// get an API error then parse the error and forward it back to the client
// in an appropriate format.
// API errors from the SDK are of type [apierr.APIError]. Forward the raw
// response bytes verbatim — including any error details — so callers see
// exactly what the workspace returned. Re-marshalling from the parsed
// APIError would drop fields the SDK doesn't surface (e.g. metadata in
// details[]) and silently break callers that inspect them.
apiErr := &apierr.APIError{}
if errors.As(err, &apiErr) {
body := map[string]string{
"error_code": apiErr.ErrorCode,
"message": apiErr.Message,
rw := apiErr.ResponseWrapper
if rw == nil {
// The SDK populates ResponseWrapper for every APIError produced
// from a real HTTP response. If this ever fires the SDK changed
// shape and we need to revisit how we forward error bodies.
panic("apierr.APIError has no ResponseWrapper")
}

b, err := json.Marshal(body)
assert.NoError(s.t, err)

encodedResponse = &testserver.EncodedResponse{
StatusCode: apiErr.StatusCode,
Body: b,
StatusCode: rw.Response.StatusCode,
Body: rw.DebugBytes,
}
// Visitors registered via WithResponseHeader are not invoked when
// the SDK returns an error, so populate the include list directly
// from the original response headers.
for _, header := range includeResponseHeaders {
if v := rw.Response.Header.Get(header); v != "" {
*responseHeaders[header] = v
}
}
}

Expand Down
Loading