Report quota resource categories in CLI errors

This commit is contained in:
Michel Paulissen 2026-07-04 11:37:29 +02:00
parent eb8dc3bf12
commit 1c4b045a6a
4 changed files with 87 additions and 5 deletions

View file

@ -2759,7 +2759,7 @@ fn cli_error_summary_with_default(message: &str, default_category: &'static str)
}
fn cli_error_summary_for_category(category: &'static str, message: &str) -> Value {
json!({
let mut summary = json!({
"category": category,
"stable_exit_code": cli_error_exit_code(category),
"process_exit_code_applied": false,
@ -2767,7 +2767,56 @@ fn cli_error_summary_for_category(category: &'static str, message: &str) -> Valu
"message": message,
"safe_failure": true,
"next_actions": cli_error_next_actions(category),
})
});
if category == "quota" {
if let Some(object) = summary.as_object_mut() {
object.insert(
"resource_category".to_owned(),
json!(
quota_error_resource_category(message).unwrap_or_else(|| "unknown".to_owned())
),
);
object.insert("community_tier_language".to_owned(), json!(true));
object.insert("private_abuse_heuristics_exposed".to_owned(), json!(false));
}
}
summary
}
fn quota_error_resource_category(message: &str) -> Option<String> {
let lower = message.to_ascii_lowercase();
for marker in [
"resource limit exceeded for ",
"quota unavailable for ",
"quota exceeded for ",
"limit exceeded for ",
"metering limit exceeded for ",
"quota limit for ",
"resource category ",
"resource=",
"resource:",
] {
if let Some(index) = lower.find(marker) {
let start = index + marker.len();
let rest = &message[start..];
let value: String = rest
.chars()
.skip_while(|ch| ch.is_ascii_whitespace())
.take_while(|ch| {
ch.is_ascii_alphanumeric()
|| *ch == '_'
|| *ch == '-'
|| *ch == '.'
|| *ch == ':'
})
.collect();
let value = value.trim_matches(|ch: char| ch == '.' || ch == ':' || ch == ',');
if !value.is_empty() {
return Some(value.to_owned());
}
}
}
None
}
fn classify_cli_error_message(message: &str) -> &'static str {
@ -5679,7 +5728,11 @@ mod tests {
20,
),
("unauthorized tenant action", "authorization", 21),
("quota unavailable: resource limit exceeded", "quota", 22),
(
"quota unavailable: resource limit exceeded for api_calls",
"quota",
22,
),
("policy denied native command execution", "policy", 23),
(
"scheduler placement failed: no capable node for placement: project mismatch",
@ -5714,6 +5767,11 @@ mod tests {
assert_eq!(summary["safe_failure"], true);
assert_eq!(summary["process_exit_code_applied"], false);
assert!(summary["next_actions"].as_array().unwrap().len() >= 2);
if category == "quota" {
assert_eq!(summary["resource_category"], "api_calls");
assert_eq!(summary["community_tier_language"], true);
assert_eq!(summary["private_abuse_heuristics_exposed"], false);
}
}
}
@ -6118,6 +6176,12 @@ mod tests {
assert_eq!(rejected["error_category"], "quota");
assert_eq!(rejected["stable_exit_code"], 22);
assert_eq!(rejected["machine_error"]["category"], "quota");
assert_eq!(rejected["machine_error"]["resource_category"], "api_calls");
assert_eq!(rejected["machine_error"]["community_tier_language"], true);
assert_eq!(
rejected["machine_error"]["private_abuse_heuristics_exposed"],
false
);
assert!(rejected["machine_error"]["next_actions"]
.as_array()
.unwrap()