{"record":{"id":"b10865007aaac6b8","repo":"googleapis/mcp-toolbox","slug":"failed-to-list-data-products-code-s-message-s","errorCode":null,"errorMessage":"failed to list data products: code=%s message=%s","messagePattern":"failed to list data products: code=(.+?) message=(.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/sources/dataplex/dataplex.go","lineNumber":458,"sourceCode":"\tparent := fmt.Sprintf(\"projects/%s/locations/-\", s.ProjectID())\n\treq := &dataplexpb.ListDataProductsRequest{\n\t\tParent:   parent,\n\t\tFilter:   filter,\n\t\tPageSize: int32(pageSize),\n\t\tOrderBy:  orderBy,\n\t}\n\n\tit := s.GetDataProductClient().ListDataProducts(ctx, req)\n\tvar results []*DataProductSummary\n\n\tfor len(results) < pageSize {\n\t\tdp, err := it.Next()\n\t\tif err == iterator.Done {\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\tif st, ok := grpcstatus.FromError(err); ok {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to list data products: code=%s message=%s\", st.Code(), st.Message())\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(\"failed to list data products: %w\", err)\n\t\t}\n\t\tparts := strings.Split(dp.GetName(), \"/\")\n\t\tvar locID, prodID string\n\t\tif len(parts) >= 6 && parts[0] == \"projects\" && parts[2] == \"locations\" && parts[4] == \"dataProducts\" {\n\t\t\tlocID = parts[3]\n\t\t\tprodID = parts[5]\n\t\t}\n\t\tresults = append(results, &DataProductSummary{\n\t\t\tLocationID:    locID,\n\t\t\tDataProductID: prodID,\n\t\t\tDisplayName:   dp.GetDisplayName(),\n\t\t\tOwnerEmails:   dp.GetOwnerEmails(),\n\t\t\tAssetCount:    dp.GetAssetCount(),\n\t\t})\n\t}\n\treturn results, nil","sourceCodeStart":440,"sourceCodeEnd":476,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/sources/dataplex/dataplex.go#L440-L476","documentation":"While iterating DataProduct results in ListDataProducts, the underlying call returned a gRPC error with a structured status. The library extracts the status code and message and returns them in this formatted error so the API-reported failure reason (e.g. PERMISSION_DENIED, INVALID_ARGUMENT) is directly visible.","triggerScenarios":"The ListDataProducts iterator's Next() returns a gRPC status error, typically because the parent 'projects/{project}/locations/-' is malformed, the caller lacks dataplex.dataProducts.list IAM permission, the filter/orderBy string is invalid, or the project/location does not exist.","commonSituations":"Service account missing roles/dataplex.viewer; typo in project ID; invalid filter syntax such as an unknown field; calling against a project where the Dataplex API is not enabled.","solutions":["Read the embedded code= and message= to identify the exact gRPC status.","Verify the service account has dataplex.dataProducts.list permission (grant roles/dataplex.viewer or equivalent).","Confirm the Dataplex API is enabled on the project (gcloud services enable dataplex.googleapis.com).","Check the project ID and filter/orderBy syntax against the Dataplex ListDataProducts API reference."],"exampleFix":"// before (bad filter)\nfilter := \"system = unknown\"\n// after (valid filter)\nfilter := \"system = BIGQUERY\"","handlingStrategy":"try-catch","validationCode":"// preflight permission/parent check\nif projectID == \"\" || !strings.Contains(projectID, \"-\") == false && projectID == \"\" { /* validate non-empty project */ }\nif projectID == \"\" { return errors.New(\"project ID must be non-empty\") }","typeGuard":"func isPermissionDenied(err error) bool {\n\tst, ok := status.FromError(err)\n\treturn ok && st.Code() == codes.PermissionDenied\n}","tryCatchPattern":"products, err := src.ListDataProducts(ctx, filter, pageSize, orderBy)\nif err != nil {\n\tvar re *googleapi.Error\n\tif isPermissionDenied(err) {\n\t\treturn fmt.Errorf(\"grant roles/dataplex.viewer to the service account: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Grant roles/dataplex.viewer (or dataProducts.list IAM) to the service account before use.","Enable dataplex.googleapis.com on the target project.","Validate project ID and filter/orderBy syntax against the API reference.","Keep filter expressions simple and field names verified."],"tags":["gcp","dataplex","grpc","iam","permissions"],"backgroundTag":"grpc-permission-denied","analyzedSha":"8cc6e09de2ad7b8bffc77751799585a1401a48eb","analyzedAt":"2026-09-05T01:10:36.887Z","contentChangedAt":"2026-09-05T01:10:36.887Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}