Skip to content

Commit 1d7c498

Browse files
mahlevanshikaduwenxin99averikitsch
authored
fix(dataplex): Capture GCP HTTP errors in MCP Toolbox (#2347)
### Description fix: Surface Dataplex API errors in MCP results This change addresses issue #2203, where Dataplex API errors, such as '403 Forbidden' (Permission Denied), were not being properly surfaced in the MCP tool results. Previously, these critical API errors would manifest as generic "connection interrupted" messages, significantly hindering developer debugging and trust in the Toolbox. The fix enhances the error handling within the 'dataplexsearchentries' and 'dataplexsearchaspecttypes' tools. When an error occurs during the iteration of Dataplex API results, the system now: Utilizes 'google.golang.org/grpc/status.FromError' to attempt to convert the returned error into a gRPC status. This is crucial because Google Cloud client libraries often return errors compatible with gRPC. If the error is a gRPC status, the canonical error code (e.g., 'codes.PermissionDenied') and the associated error message are extracted. This ensures that users receive clear actionable error feedback, allowing for quicker diagnosis and resolution of issues like missing IAM permissions. This aligns with best practices for API error surfacing, improving the usability and reliability of the Dataplex tools within the GenAI Toolbox. Fixes #2203 ## PR Checklist > Thank you for opening a Pull Request! Before submitting your PR, there are a > few things you can do to make sure it goes smoothly: - [ ] Make sure you reviewed [CONTRIBUTING.md](https://github.com/googleapis/genai-toolbox/blob/main/CONTRIBUTING.md) - [ ] Make sure to open an issue as a [bug/issue](https://github.com/googleapis/genai-toolbox/issues/new/choose) before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea - [ ] Ensure the tests and linter pass - [ ] Code coverage does not decrease (if any source code was changed) - [ ] Appropriate docs were updated (if necessary) - [ ] Make sure to add `!` if this involve a breaking change 🛠️ Fixes #<issue_number_goes_here> --------- Co-authored-by: Wenxin Du <117315983+duwenxin99@users.noreply.github.com> Co-authored-by: Averi Kitsch <akitsch@google.com>
1 parent 9294ce3 commit 1d7c498

3 files changed

Lines changed: 23 additions & 3 deletions

File tree

.github/workflows/link_checker_workflow.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ jobs:
3939
--no-progress
4040
--cache
4141
--max-cache-age 1d
42+
--exclude '^neo4j\+.*' --exclude '^bolt://.*'
4243
README.md
4344
docs/
4445
output: /tmp/foo.txt

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ require (
6363
google.golang.org/api v0.256.0
6464
google.golang.org/genai v1.37.0
6565
google.golang.org/genproto v0.0.0-20251022142026-3a174f9686a8
66+
google.golang.org/grpc v1.76.0
6667
google.golang.org/protobuf v1.36.10
6768
modernc.org/sqlite v1.40.0
6869
)
@@ -229,7 +230,6 @@ require (
229230
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
230231
google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba // indirect
231232
google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101 // indirect
232-
google.golang.org/grpc v1.76.0 // indirect
233233
gopkg.in/inf.v0 v0.9.1 // indirect
234234
gopkg.in/ini.v1 v1.67.0 // indirect
235235
modernc.org/libc v1.66.10 // indirect

internal/sources/dataplex/dataplex.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ import (
2626
"github.com/googleapis/genai-toolbox/internal/util"
2727
"go.opentelemetry.io/otel/trace"
2828
"golang.org/x/oauth2/google"
29+
"google.golang.org/api/iterator"
2930
"google.golang.org/api/option"
31+
grpcstatus "google.golang.org/grpc/status"
3032
)
3133

3234
const SourceKind string = "dataplex"
@@ -173,9 +175,18 @@ func (s *Source) SearchAspectTypes(ctx context.Context, query string, pageSize i
173175
var results []*dataplexpb.AspectType
174176
for {
175177
entry, err := it.Next()
176-
if err != nil {
178+
179+
if err == iterator.Done {
177180
break
178181
}
182+
if err != nil {
183+
if st, ok := grpcstatus.FromError(err); ok {
184+
errorCode := st.Code()
185+
errorMessage := st.Message()
186+
return nil, fmt.Errorf("failed to search aspect types with error code: %q message: %s", errorCode.String(), errorMessage)
187+
}
188+
return nil, fmt.Errorf("failed to search aspect types: %w", err)
189+
}
179190

180191
// Create an instance of exponential backoff with default values for retrying GetAspectType calls
181192
// InitialInterval, RandomizationFactor, Multiplier, MaxInterval = 500 ms, 0.5, 1.5, 60 s
@@ -214,9 +225,17 @@ func (s *Source) SearchEntries(ctx context.Context, query string, pageSize int,
214225
var results []*dataplexpb.SearchEntriesResult
215226
for {
216227
entry, err := it.Next()
217-
if err != nil {
228+
if err == iterator.Done {
218229
break
219230
}
231+
if err != nil {
232+
if st, ok := grpcstatus.FromError(err); ok {
233+
errorCode := st.Code()
234+
errorMessage := st.Message()
235+
return nil, fmt.Errorf("failed to search entries with error code: %q message: %s", errorCode.String(), errorMessage)
236+
}
237+
return nil, fmt.Errorf("failed to search entries: %w", err)
238+
}
220239
results = append(results, entry)
221240
}
222241
return results, nil

0 commit comments

Comments
 (0)