Skip to content

Commit e7e4990

Browse files
update error details
1 parent df9af05 commit e7e4990

File tree

6 files changed

+242
-12
lines changed

6 files changed

+242
-12
lines changed

Sources/GRPCProtobuf/Errors/Generated/code.pb.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// For information on using the generated types, please see the documentation:
99
// https://github.com/apple/swift-protobuf/
1010

11-
// Copyright 2024 Google LLC
11+
// Copyright 2025 Google LLC
1212
//
1313
// Licensed under the Apache License, Version 2.0 (the "License");
1414
// you may not use this file except in compliance with the License.

Sources/GRPCProtobuf/Errors/Generated/error_details.pb.swift

Lines changed: 156 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// For information on using the generated types, please see the documentation:
99
// https://github.com/apple/swift-protobuf/
1010

11-
// Copyright 2024 Google LLC
11+
// Copyright 2025 Google LLC
1212
//
1313
// Licensed under the Apache License, Version 2.0 (the "License");
1414
// you may not use this file except in compliance with the License.
@@ -80,11 +80,12 @@ struct Google_Rpc_ErrorInfo: Sendable {
8080

8181
/// Additional structured details about this error.
8282
///
83-
/// Keys should match /[a-zA-Z0-9-_]/ and be limited to 64 characters in
83+
/// Keys must match a regular expression of `[a-z][a-zA-Z0-9-_]+` but should
84+
/// ideally be lowerCamelCase. Also, they must be limited to 64 characters in
8485
/// length. When identifying the current value of an exceeded limit, the units
8586
/// should be contained in the key, not the value. For example, rather than
86-
/// {"instanceLimit": "100/request"}, should be returned as,
87-
/// {"instanceLimitPerRequest": "100"}, if the client exceeds the number of
87+
/// `{"instanceLimit": "100/request"}`, should be returned as,
88+
/// `{"instanceLimitPerRequest": "100"}`, if the client exceeds the number of
8889
/// instances that can be created in a single (batch) request.
8990
var metadata: Dictionary<String,String> = [:]
9091

@@ -187,9 +188,83 @@ struct Google_Rpc_QuotaFailure: Sendable {
187188
/// exceeded".
188189
var description_p: String = String()
189190

191+
/// The API Service from which the `QuotaFailure.Violation` orginates. In
192+
/// some cases, Quota issues originate from an API Service other than the one
193+
/// that was called. In other words, a dependency of the called API Service
194+
/// could be the cause of the `QuotaFailure`, and this field would have the
195+
/// dependency API service name.
196+
///
197+
/// For example, if the called API is Kubernetes Engine API
198+
/// (container.googleapis.com), and a quota violation occurs in the
199+
/// Kubernetes Engine API itself, this field would be
200+
/// "container.googleapis.com". On the other hand, if the quota violation
201+
/// occurs when the Kubernetes Engine API creates VMs in the Compute Engine
202+
/// API (compute.googleapis.com), this field would be
203+
/// "compute.googleapis.com".
204+
var apiService: String = String()
205+
206+
/// The metric of the violated quota. A quota metric is a named counter to
207+
/// measure usage, such as API requests or CPUs. When an activity occurs in a
208+
/// service, such as Virtual Machine allocation, one or more quota metrics
209+
/// may be affected.
210+
///
211+
/// For example, "compute.googleapis.com/cpus_per_vm_family",
212+
/// "storage.googleapis.com/internet_egress_bandwidth".
213+
var quotaMetric: String = String()
214+
215+
/// The id of the violated quota. Also know as "limit name", this is the
216+
/// unique identifier of a quota in the context of an API service.
217+
///
218+
/// For example, "CPUS-PER-VM-FAMILY-per-project-region".
219+
var quotaID: String = String()
220+
221+
/// The dimensions of the violated quota. Every non-global quota is enforced
222+
/// on a set of dimensions. While quota metric defines what to count, the
223+
/// dimensions specify for what aspects the counter should be increased.
224+
///
225+
/// For example, the quota "CPUs per region per VM family" enforces a limit
226+
/// on the metric "compute.googleapis.com/cpus_per_vm_family" on dimensions
227+
/// "region" and "vm_family". And if the violation occurred in region
228+
/// "us-central1" and for VM family "n1", the quota_dimensions would be,
229+
///
230+
/// {
231+
/// "region": "us-central1",
232+
/// "vm_family": "n1",
233+
/// }
234+
///
235+
/// When a quota is enforced globally, the quota_dimensions would always be
236+
/// empty.
237+
var quotaDimensions: Dictionary<String,String> = [:]
238+
239+
/// The enforced quota value at the time of the `QuotaFailure`.
240+
///
241+
/// For example, if the enforced quota value at the time of the
242+
/// `QuotaFailure` on the number of CPUs is "10", then the value of this
243+
/// field would reflect this quantity.
244+
var quotaValue: Int64 = 0
245+
246+
/// The new quota value being rolled out at the time of the violation. At the
247+
/// completion of the rollout, this value will be enforced in place of
248+
/// quota_value. If no rollout is in progress at the time of the violation,
249+
/// this field is not set.
250+
///
251+
/// For example, if at the time of the violation a rollout is in progress
252+
/// changing the number of CPUs quota from 10 to 20, 20 would be the value of
253+
/// this field.
254+
var futureQuotaValue: Int64 {
255+
get {return _futureQuotaValue ?? 0}
256+
set {_futureQuotaValue = newValue}
257+
}
258+
/// Returns true if `futureQuotaValue` has been explicitly set.
259+
var hasFutureQuotaValue: Bool {return self._futureQuotaValue != nil}
260+
/// Clears the value of `futureQuotaValue`. Subsequent reads from it will return its default value.
261+
mutating func clearFutureQuotaValue() {self._futureQuotaValue = nil}
262+
190263
var unknownFields = SwiftProtobuf.UnknownStorage()
191264

192265
init() {}
266+
267+
fileprivate var _futureQuotaValue: Int64? = nil
193268
}
194269

195270
init() {}
@@ -300,9 +375,30 @@ struct Google_Rpc_BadRequest: Sendable {
300375
/// A description of why the request element is bad.
301376
var description_p: String = String()
302377

378+
/// The reason of the field-level error. This is a constant value that
379+
/// identifies the proximate cause of the field-level error. It should
380+
/// uniquely identify the type of the FieldViolation within the scope of the
381+
/// google.rpc.ErrorInfo.domain. This should be at most 63
382+
/// characters and match a regular expression of `[A-Z][A-Z0-9_]+[A-Z0-9]`,
383+
/// which represents UPPER_SNAKE_CASE.
384+
var reason: String = String()
385+
386+
/// Provides a localized error message for field-level errors that is safe to
387+
/// return to the API consumer.
388+
var localizedMessage: Google_Rpc_LocalizedMessage {
389+
get {return _localizedMessage ?? Google_Rpc_LocalizedMessage()}
390+
set {_localizedMessage = newValue}
391+
}
392+
/// Returns true if `localizedMessage` has been explicitly set.
393+
var hasLocalizedMessage: Bool {return self._localizedMessage != nil}
394+
/// Clears the value of `localizedMessage`. Subsequent reads from it will return its default value.
395+
mutating func clearLocalizedMessage() {self._localizedMessage = nil}
396+
303397
var unknownFields = SwiftProtobuf.UnknownStorage()
304398

305399
init() {}
400+
401+
fileprivate var _localizedMessage: Google_Rpc_LocalizedMessage? = nil
306402
}
307403

308404
init() {}
@@ -574,6 +670,12 @@ extension Google_Rpc_QuotaFailure.Violation: SwiftProtobuf.Message, SwiftProtobu
574670
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
575671
1: .same(proto: "subject"),
576672
2: .same(proto: "description"),
673+
3: .standard(proto: "api_service"),
674+
4: .standard(proto: "quota_metric"),
675+
5: .standard(proto: "quota_id"),
676+
6: .standard(proto: "quota_dimensions"),
677+
7: .standard(proto: "quota_value"),
678+
8: .standard(proto: "future_quota_value"),
577679
]
578680

579681
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
@@ -584,24 +686,58 @@ extension Google_Rpc_QuotaFailure.Violation: SwiftProtobuf.Message, SwiftProtobu
584686
switch fieldNumber {
585687
case 1: try { try decoder.decodeSingularStringField(value: &self.subject) }()
586688
case 2: try { try decoder.decodeSingularStringField(value: &self.description_p) }()
689+
case 3: try { try decoder.decodeSingularStringField(value: &self.apiService) }()
690+
case 4: try { try decoder.decodeSingularStringField(value: &self.quotaMetric) }()
691+
case 5: try { try decoder.decodeSingularStringField(value: &self.quotaID) }()
692+
case 6: try { try decoder.decodeMapField(fieldType: SwiftProtobuf._ProtobufMap<SwiftProtobuf.ProtobufString,SwiftProtobuf.ProtobufString>.self, value: &self.quotaDimensions) }()
693+
case 7: try { try decoder.decodeSingularInt64Field(value: &self.quotaValue) }()
694+
case 8: try { try decoder.decodeSingularInt64Field(value: &self._futureQuotaValue) }()
587695
default: break
588696
}
589697
}
590698
}
591699

592700
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
701+
// The use of inline closures is to circumvent an issue where the compiler
702+
// allocates stack space for every if/case branch local when no optimizations
703+
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
704+
// https://github.com/apple/swift-protobuf/issues/1182
593705
if !self.subject.isEmpty {
594706
try visitor.visitSingularStringField(value: self.subject, fieldNumber: 1)
595707
}
596708
if !self.description_p.isEmpty {
597709
try visitor.visitSingularStringField(value: self.description_p, fieldNumber: 2)
598710
}
711+
if !self.apiService.isEmpty {
712+
try visitor.visitSingularStringField(value: self.apiService, fieldNumber: 3)
713+
}
714+
if !self.quotaMetric.isEmpty {
715+
try visitor.visitSingularStringField(value: self.quotaMetric, fieldNumber: 4)
716+
}
717+
if !self.quotaID.isEmpty {
718+
try visitor.visitSingularStringField(value: self.quotaID, fieldNumber: 5)
719+
}
720+
if !self.quotaDimensions.isEmpty {
721+
try visitor.visitMapField(fieldType: SwiftProtobuf._ProtobufMap<SwiftProtobuf.ProtobufString,SwiftProtobuf.ProtobufString>.self, value: self.quotaDimensions, fieldNumber: 6)
722+
}
723+
if self.quotaValue != 0 {
724+
try visitor.visitSingularInt64Field(value: self.quotaValue, fieldNumber: 7)
725+
}
726+
try { if let v = self._futureQuotaValue {
727+
try visitor.visitSingularInt64Field(value: v, fieldNumber: 8)
728+
} }()
599729
try unknownFields.traverse(visitor: &visitor)
600730
}
601731

602732
static func ==(lhs: Google_Rpc_QuotaFailure.Violation, rhs: Google_Rpc_QuotaFailure.Violation) -> Bool {
603733
if lhs.subject != rhs.subject {return false}
604734
if lhs.description_p != rhs.description_p {return false}
735+
if lhs.apiService != rhs.apiService {return false}
736+
if lhs.quotaMetric != rhs.quotaMetric {return false}
737+
if lhs.quotaID != rhs.quotaID {return false}
738+
if lhs.quotaDimensions != rhs.quotaDimensions {return false}
739+
if lhs.quotaValue != rhs.quotaValue {return false}
740+
if lhs._futureQuotaValue != rhs._futureQuotaValue {return false}
605741
if lhs.unknownFields != rhs.unknownFields {return false}
606742
return true
607743
}
@@ -720,6 +856,8 @@ extension Google_Rpc_BadRequest.FieldViolation: SwiftProtobuf.Message, SwiftProt
720856
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
721857
1: .same(proto: "field"),
722858
2: .same(proto: "description"),
859+
3: .same(proto: "reason"),
860+
4: .standard(proto: "localized_message"),
723861
]
724862

725863
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
@@ -730,24 +868,38 @@ extension Google_Rpc_BadRequest.FieldViolation: SwiftProtobuf.Message, SwiftProt
730868
switch fieldNumber {
731869
case 1: try { try decoder.decodeSingularStringField(value: &self.field) }()
732870
case 2: try { try decoder.decodeSingularStringField(value: &self.description_p) }()
871+
case 3: try { try decoder.decodeSingularStringField(value: &self.reason) }()
872+
case 4: try { try decoder.decodeSingularMessageField(value: &self._localizedMessage) }()
733873
default: break
734874
}
735875
}
736876
}
737877

738878
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
879+
// The use of inline closures is to circumvent an issue where the compiler
880+
// allocates stack space for every if/case branch local when no optimizations
881+
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
882+
// https://github.com/apple/swift-protobuf/issues/1182
739883
if !self.field.isEmpty {
740884
try visitor.visitSingularStringField(value: self.field, fieldNumber: 1)
741885
}
742886
if !self.description_p.isEmpty {
743887
try visitor.visitSingularStringField(value: self.description_p, fieldNumber: 2)
744888
}
889+
if !self.reason.isEmpty {
890+
try visitor.visitSingularStringField(value: self.reason, fieldNumber: 3)
891+
}
892+
try { if let v = self._localizedMessage {
893+
try visitor.visitSingularMessageField(value: v, fieldNumber: 4)
894+
} }()
745895
try unknownFields.traverse(visitor: &visitor)
746896
}
747897

748898
static func ==(lhs: Google_Rpc_BadRequest.FieldViolation, rhs: Google_Rpc_BadRequest.FieldViolation) -> Bool {
749899
if lhs.field != rhs.field {return false}
750900
if lhs.description_p != rhs.description_p {return false}
901+
if lhs.reason != rhs.reason {return false}
902+
if lhs._localizedMessage != rhs._localizedMessage {return false}
751903
if lhs.unknownFields != rhs.unknownFields {return false}
752904
return true
753905
}

Sources/GRPCProtobuf/Errors/Generated/status.pb.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// For information on using the generated types, please see the documentation:
99
// https://github.com/apple/swift-protobuf/
1010

11-
// Copyright 2024 Google LLC
11+
// Copyright 2025 Google LLC
1212
//
1313
// Licensed under the Apache License, Version 2.0 (the "License");
1414
// you may not use this file except in compliance with the License.

dev/protos/upstream/google/rpc/code.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2024 Google LLC
1+
// Copyright 2025 Google LLC
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.

dev/protos/upstream/google/rpc/error_details.proto

Lines changed: 82 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2024 Google LLC
1+
// Copyright 2025 Google LLC
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -66,11 +66,12 @@ message ErrorInfo {
6666

6767
// Additional structured details about this error.
6868
//
69-
// Keys should match /[a-zA-Z0-9-_]/ and be limited to 64 characters in
69+
// Keys must match a regular expression of `[a-z][a-zA-Z0-9-_]+` but should
70+
// ideally be lowerCamelCase. Also, they must be limited to 64 characters in
7071
// length. When identifying the current value of an exceeded limit, the units
7172
// should be contained in the key, not the value. For example, rather than
72-
// {"instanceLimit": "100/request"}, should be returned as,
73-
// {"instanceLimitPerRequest": "100"}, if the client exceeds the number of
73+
// `{"instanceLimit": "100/request"}`, should be returned as,
74+
// `{"instanceLimitPerRequest": "100"}`, if the client exceeds the number of
7475
// instances that can be created in a single (batch) request.
7576
map<string, string> metadata = 3;
7677
}
@@ -130,6 +131,71 @@ message QuotaFailure {
130131
// For example: "Service disabled" or "Daily Limit for read operations
131132
// exceeded".
132133
string description = 2;
134+
135+
// The API Service from which the `QuotaFailure.Violation` orginates. In
136+
// some cases, Quota issues originate from an API Service other than the one
137+
// that was called. In other words, a dependency of the called API Service
138+
// could be the cause of the `QuotaFailure`, and this field would have the
139+
// dependency API service name.
140+
//
141+
// For example, if the called API is Kubernetes Engine API
142+
// (container.googleapis.com), and a quota violation occurs in the
143+
// Kubernetes Engine API itself, this field would be
144+
// "container.googleapis.com". On the other hand, if the quota violation
145+
// occurs when the Kubernetes Engine API creates VMs in the Compute Engine
146+
// API (compute.googleapis.com), this field would be
147+
// "compute.googleapis.com".
148+
string api_service = 3;
149+
150+
// The metric of the violated quota. A quota metric is a named counter to
151+
// measure usage, such as API requests or CPUs. When an activity occurs in a
152+
// service, such as Virtual Machine allocation, one or more quota metrics
153+
// may be affected.
154+
//
155+
// For example, "compute.googleapis.com/cpus_per_vm_family",
156+
// "storage.googleapis.com/internet_egress_bandwidth".
157+
string quota_metric = 4;
158+
159+
// The id of the violated quota. Also know as "limit name", this is the
160+
// unique identifier of a quota in the context of an API service.
161+
//
162+
// For example, "CPUS-PER-VM-FAMILY-per-project-region".
163+
string quota_id = 5;
164+
165+
// The dimensions of the violated quota. Every non-global quota is enforced
166+
// on a set of dimensions. While quota metric defines what to count, the
167+
// dimensions specify for what aspects the counter should be increased.
168+
//
169+
// For example, the quota "CPUs per region per VM family" enforces a limit
170+
// on the metric "compute.googleapis.com/cpus_per_vm_family" on dimensions
171+
// "region" and "vm_family". And if the violation occurred in region
172+
// "us-central1" and for VM family "n1", the quota_dimensions would be,
173+
//
174+
// {
175+
// "region": "us-central1",
176+
// "vm_family": "n1",
177+
// }
178+
//
179+
// When a quota is enforced globally, the quota_dimensions would always be
180+
// empty.
181+
map<string, string> quota_dimensions = 6;
182+
183+
// The enforced quota value at the time of the `QuotaFailure`.
184+
//
185+
// For example, if the enforced quota value at the time of the
186+
// `QuotaFailure` on the number of CPUs is "10", then the value of this
187+
// field would reflect this quantity.
188+
int64 quota_value = 7;
189+
190+
// The new quota value being rolled out at the time of the violation. At the
191+
// completion of the rollout, this value will be enforced in place of
192+
// quota_value. If no rollout is in progress at the time of the violation,
193+
// this field is not set.
194+
//
195+
// For example, if at the time of the violation a rollout is in progress
196+
// changing the number of CPUs quota from 10 to 20, 20 would be the value of
197+
// this field.
198+
optional int64 future_quota_value = 8;
133199
}
134200

135201
// Describes all quota violations.
@@ -211,6 +277,18 @@ message BadRequest {
211277

212278
// A description of why the request element is bad.
213279
string description = 2;
280+
281+
// The reason of the field-level error. This is a constant value that
282+
// identifies the proximate cause of the field-level error. It should
283+
// uniquely identify the type of the FieldViolation within the scope of the
284+
// google.rpc.ErrorInfo.domain. This should be at most 63
285+
// characters and match a regular expression of `[A-Z][A-Z0-9_]+[A-Z0-9]`,
286+
// which represents UPPER_SNAKE_CASE.
287+
string reason = 3;
288+
289+
// Provides a localized error message for field-level errors that is safe to
290+
// return to the API consumer.
291+
LocalizedMessage localized_message = 4;
214292
}
215293

216294
// Describes all violations in a client request.

0 commit comments

Comments
 (0)