api: expose structured runtime error context

This commit is contained in:
a.tolmachev
2026-04-19 21:32:56 +00:00
parent 5debf4dd05
commit af511316ba
2 changed files with 230 additions and 9 deletions
+90 -2
View File
@@ -231,10 +231,14 @@ impl From<StorageError> for ApiError {
}
pub fn runtime_test_failure(error: &RuntimeError) -> Value {
json!({
let mut payload = json!({
"code": runtime_test_failure_code(error),
"message": error.to_string()
})
});
if let Some(context) = runtime_error_context(error) {
payload["context"] = context;
}
payload
}
fn runtime_test_failure_code(error: &RuntimeError) -> &'static str {
@@ -259,3 +263,87 @@ fn runtime_test_failure_code(error: &RuntimeError) -> &'static str {
RuntimeError::SecretCrypto { .. } => "runtime_secret_crypto_error",
}
}
pub fn runtime_error_context(error: &RuntimeError) -> Option<Value> {
match error {
RuntimeError::InvalidPreparedRequest { field, reason } => Some(json!({
"field": field,
"reason": reason,
})),
RuntimeError::InvalidStreamingPayload { field, reason } => Some(json!({
"field": field,
"reason": reason,
})),
RuntimeError::InvalidAuthSecretValue { secret_id, reason } => Some(json!({
"secret_id": secret_id,
"reason": reason,
})),
RuntimeError::SecretCrypto { operation, details } => Some(json!({
"operation": operation,
"details": details,
})),
RuntimeError::MissingAuthProfile { auth_profile_id } => Some(json!({
"auth_profile_id": auth_profile_id,
})),
RuntimeError::MissingSecret { secret_id } => Some(json!({
"secret_id": secret_id,
})),
RuntimeError::MissingSecretVersion { secret_id, version } => Some(json!({
"secret_id": secret_id,
"version": version,
})),
RuntimeError::MissingStreamingConfig { operation_id } => Some(json!({
"operation_id": operation_id,
})),
RuntimeError::UnsupportedExecutionMode { operation_id, mode } => Some(json!({
"operation_id": operation_id,
"mode": mode,
})),
RuntimeError::UnsupportedProtocol { protocol } => Some(json!({
"protocol": protocol,
})),
_ => None,
}
}
#[cfg(test)]
mod tests {
use serde_json::json;
use super::{runtime_error_context, runtime_test_failure};
use crank_runtime::RuntimeError;
#[test]
fn runtime_test_failure_includes_structured_context() {
let payload = runtime_test_failure(&RuntimeError::InvalidPreparedRequest {
field: "request.headers".to_owned(),
reason: "must be an object".to_owned(),
});
assert_eq!(payload["code"], "runtime_request_error");
assert_eq!(
payload["context"],
json!({
"field": "request.headers",
"reason": "must be an object"
})
);
}
#[test]
fn runtime_error_context_includes_secret_crypto_operation() {
let context = runtime_error_context(&RuntimeError::SecretCrypto {
operation: "decode secret envelope",
details: "bad base64".to_owned(),
})
.unwrap();
assert_eq!(
context,
json!({
"operation": "decode secret envelope",
"details": "bad base64"
})
);
}
}