Frontend failure text updates (#1300)

This commit is contained in:
Brandon Thomas
2026-04-03 18:20:06 -04:00
committed by GitHub
parent f55a4c722e
commit 99b5a9774a
6 changed files with 76 additions and 8 deletions
@@ -20,6 +20,9 @@ pub enum FrontendFailureCategoryForApiClients {
RuleBansGeneratedVideo,
RuleBansGeneratedAudio,
RuleBansGeneratedContent,
FilesizeTooLarge,
ImageDimensionsTooSmall,
ImageDimensionsTooLarge,
GenerationFailed,
/// Catch-all for values the client doesn't yet know about.
@@ -43,6 +46,9 @@ impl FrontendFailureCategoryForApiClients {
FrontendFailureCategory::RuleBansGeneratedVideo => Self::RuleBansGeneratedVideo,
FrontendFailureCategory::RuleBansGeneratedAudio => Self::RuleBansGeneratedAudio,
FrontendFailureCategory::RuleBansGeneratedContent => Self::RuleBansGeneratedContent,
FrontendFailureCategory::FilesizeTooLarge => Self::FilesizeTooLarge,
FrontendFailureCategory::ImageDimensionsTooSmall => Self::ImageDimensionsTooSmall,
FrontendFailureCategory::ImageDimensionsTooLarge => Self::ImageDimensionsTooLarge,
FrontendFailureCategory::GenerationFailed => Self::GenerationFailed,
}
}
@@ -67,6 +73,9 @@ mod tests {
("\"rule_bans_generated_video\"", FrontendFailureCategoryForApiClients::RuleBansGeneratedVideo),
("\"rule_bans_generated_audio\"", FrontendFailureCategoryForApiClients::RuleBansGeneratedAudio),
("\"rule_bans_generated_content\"", FrontendFailureCategoryForApiClients::RuleBansGeneratedContent),
("\"filesize_too_large\"", FrontendFailureCategoryForApiClients::FilesizeTooLarge),
("\"image_dimensions_too_small\"", FrontendFailureCategoryForApiClients::ImageDimensionsTooSmall),
("\"image_dimensions_too_large\"", FrontendFailureCategoryForApiClients::ImageDimensionsTooLarge),
("\"generation_failed\"", FrontendFailureCategoryForApiClients::GenerationFailed),
];
@@ -69,6 +69,9 @@ mod tests {
assert_eq!(FrontendFailureCategoryForOldClients::try_from_db_enum(FrontendFailureCategory::RuleBansGeneratedAudio), None);
assert_eq!(FrontendFailureCategoryForOldClients::try_from_db_enum(FrontendFailureCategory::RuleBansGeneratedContent), None);
assert_eq!(FrontendFailureCategoryForOldClients::try_from_db_enum(FrontendFailureCategory::GenerationFailed), None);
assert_eq!(FrontendFailureCategoryForOldClients::try_from_db_enum(FrontendFailureCategory::FilesizeTooLarge), None);
assert_eq!(FrontendFailureCategoryForOldClients::try_from_db_enum(FrontendFailureCategory::ImageDimensionsTooSmall), None);
assert_eq!(FrontendFailureCategoryForOldClients::try_from_db_enum(FrontendFailureCategory::ImageDimensionsTooLarge), None);
}
#[test]
@@ -69,6 +69,7 @@ pub enum FrontendFailureCategory {
/// Model content violation
/// Model content rules prohibit user content. (I think this check happens early.)
/// e.g. "Content violates platform rules. Please modify and try again." (seedance2pro)
/// We also map fal WebhookErrorType::ContentPolicyViolation to this.
#[serde(rename = "rule_bans_user_content")]
RuleBansUserContent,
@@ -90,6 +91,21 @@ pub enum FrontendFailureCategory {
#[serde(rename = "rule_bans_generated_content")]
RuleBansGeneratedContent,
/// The uploaded file exceeds the maximum allowed size for this model.
/// We map fal WebhookErrorType::FileTooLarge to this.
#[serde(rename = "filesize_too_large")]
FilesizeTooLarge,
/// The uploaded image dimensions are below the minimum required by the model.
/// We map fal WebhookErrorType::ImageTooSmall to this.
#[serde(rename = "image_dimensions_too_small")]
ImageDimensionsTooSmall,
/// The uploaded image dimensions exceed the maximum allowed by the model.
/// We map fal WebhookErrorType::ImageTooLarge to this.
#[serde(rename = "image_dimensions_too_large")]
ImageDimensionsTooLarge,
/// Generation failed (no reason)
/// Unspecified failure reason
/// Various example failures:
@@ -119,6 +135,9 @@ impl FrontendFailureCategory {
Self::RuleBansGeneratedVideo => "rule_bans_generated_video",
Self::RuleBansGeneratedAudio => "rule_bans_generated_audio",
Self::RuleBansGeneratedContent => "rule_bans_generated_content",
Self::FilesizeTooLarge => "filesize_too_large",
Self::ImageDimensionsTooSmall => "image_dimensions_too_small",
Self::ImageDimensionsTooLarge => "image_dimensions_too_large",
Self::GenerationFailed => "generation_failed",
}
}
@@ -137,6 +156,9 @@ impl FrontendFailureCategory {
"rule_bans_generated_video" => Ok(Self::RuleBansGeneratedVideo),
"rule_bans_generated_audio" => Ok(Self::RuleBansGeneratedAudio),
"rule_bans_generated_content" => Ok(Self::RuleBansGeneratedContent),
"filesize_too_large" => Ok(Self::FilesizeTooLarge),
"image_dimensions_too_small" => Ok(Self::ImageDimensionsTooSmall),
"image_dimensions_too_large" => Ok(Self::ImageDimensionsTooLarge),
"generation_failed" => Ok(Self::GenerationFailed),
_ => Err(format!("invalid value: {:?}", value)),
}
@@ -158,6 +180,9 @@ impl FrontendFailureCategory {
Self::RuleBansGeneratedVideo,
Self::RuleBansGeneratedAudio,
Self::RuleBansGeneratedContent,
Self::FilesizeTooLarge,
Self::ImageDimensionsTooSmall,
Self::ImageDimensionsTooLarge,
Self::GenerationFailed,
])
}
@@ -185,6 +210,9 @@ mod tests {
assert_serialization(FrontendFailureCategory::RuleBansGeneratedVideo, "rule_bans_generated_video");
assert_serialization(FrontendFailureCategory::RuleBansGeneratedAudio, "rule_bans_generated_audio");
assert_serialization(FrontendFailureCategory::RuleBansGeneratedContent, "rule_bans_generated_content");
assert_serialization(FrontendFailureCategory::FilesizeTooLarge, "filesize_too_large");
assert_serialization(FrontendFailureCategory::ImageDimensionsTooSmall, "image_dimensions_too_small");
assert_serialization(FrontendFailureCategory::ImageDimensionsTooLarge, "image_dimensions_too_large");
assert_serialization(FrontendFailureCategory::GenerationFailed, "generation_failed");
}
@@ -202,6 +230,9 @@ mod tests {
assert_eq!(FrontendFailureCategory::RuleBansGeneratedVideo.to_str(), "rule_bans_generated_video");
assert_eq!(FrontendFailureCategory::RuleBansGeneratedAudio.to_str(), "rule_bans_generated_audio");
assert_eq!(FrontendFailureCategory::RuleBansGeneratedContent.to_str(), "rule_bans_generated_content");
assert_eq!(FrontendFailureCategory::FilesizeTooLarge.to_str(), "filesize_too_large");
assert_eq!(FrontendFailureCategory::ImageDimensionsTooSmall.to_str(), "image_dimensions_too_small");
assert_eq!(FrontendFailureCategory::ImageDimensionsTooLarge.to_str(), "image_dimensions_too_large");
assert_eq!(FrontendFailureCategory::GenerationFailed.to_str(), "generation_failed");
}
@@ -219,6 +250,9 @@ mod tests {
assert_eq!(FrontendFailureCategory::from_str("rule_bans_generated_video").unwrap(), FrontendFailureCategory::RuleBansGeneratedVideo);
assert_eq!(FrontendFailureCategory::from_str("rule_bans_generated_audio").unwrap(), FrontendFailureCategory::RuleBansGeneratedAudio);
assert_eq!(FrontendFailureCategory::from_str("rule_bans_generated_content").unwrap(), FrontendFailureCategory::RuleBansGeneratedContent);
assert_eq!(FrontendFailureCategory::from_str("filesize_too_large").unwrap(), FrontendFailureCategory::FilesizeTooLarge);
assert_eq!(FrontendFailureCategory::from_str("image_dimensions_too_small").unwrap(), FrontendFailureCategory::ImageDimensionsTooSmall);
assert_eq!(FrontendFailureCategory::from_str("image_dimensions_too_large").unwrap(), FrontendFailureCategory::ImageDimensionsTooLarge);
assert_eq!(FrontendFailureCategory::from_str("generation_failed").unwrap(), FrontendFailureCategory::GenerationFailed);
assert_eq!(FrontendFailureCategory::from_str("invalid_value").is_err(), true);
}
@@ -226,7 +260,7 @@ mod tests {
#[test]
fn all_variants() {
let mut variants = FrontendFailureCategory::all_variants();
assert_eq!(variants.len(), 13);
assert_eq!(variants.len(), 16);
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::FaceNotDetected));
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::KeepAliveElapsed));
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::NotYetImplemented));
@@ -239,6 +273,9 @@ mod tests {
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::RuleBansGeneratedVideo));
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::RuleBansGeneratedAudio));
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::RuleBansGeneratedContent));
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::FilesizeTooLarge));
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::ImageDimensionsTooSmall));
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::ImageDimensionsTooLarge));
assert_eq!(variants.pop_first(), Some(FrontendFailureCategory::GenerationFailed));
assert_eq!(variants.pop_first(), None);
}
@@ -261,5 +298,19 @@ mod tests {
assert_eq!(variant, FrontendFailureCategory::from_str(&format!("{:?}", variant)).unwrap());
}
}
/// The database column is VARCHAR(32). Every serialized variant must fit.
#[test]
fn max_serialization_length() {
const MAX_LENGTH: usize = 32;
for variant in FrontendFailureCategory::all_variants() {
let serialized = variant.to_str();
assert!(
serialized.len() <= MAX_LENGTH,
"{:?} serializes to {:?} ({} chars), exceeds VARCHAR({}) limit",
variant, serialized, serialized.len(), MAX_LENGTH,
);
}
}
}
}
@@ -74,6 +74,9 @@ impl TaskFailureType {
FrontendFailureCategoryForApiClients::KeepAliveElapsed => Self::Unknown,
FrontendFailureCategoryForApiClients::NotYetImplemented => Self::Unknown,
FrontendFailureCategoryForApiClients::RetryableWorkerError => Self::Unknown,
FrontendFailureCategoryForApiClients::FilesizeTooLarge => Self::Unknown,
FrontendFailureCategoryForApiClients::ImageDimensionsTooSmall => Self::Unknown,
FrontendFailureCategoryForApiClients::ImageDimensionsTooLarge => Self::Unknown,
// Unknown (future-proof) variant
FrontendFailureCategoryForApiClients::Unknown(ref value) => {
@@ -1,5 +1,5 @@
use log::{error, info, warn};
use enums::by_table::generic_inference_jobs::frontend_failure_category::FrontendFailureCategory;
use mysql_queries::queries::generic_inference::job::mark_job_failed_by_token::{mark_job_failed_by_token, MarkJobFailedByTokenArgs};
use mysql_queries::queries::generic_inference::seedance2pro::list_pending_seedance2pro_character_jobs::PendingSeedance2ProCharacterJob;
use seedance2pro_client::requests::poll_characters::poll_characters::CharacterStatus;
@@ -13,7 +13,9 @@ pub async fn process_failed_character(
) {
let reason = character.fail_reason
.as_deref()
.unwrap_or("unknown failure reason");
.unwrap_or("Failure may be content related; you might be able to try again.");
let failure_category = FrontendFailureCategory::RuleBansUserContent;
warn!(
"Character {} (job {}) failed: {}",
@@ -33,7 +35,7 @@ pub async fn process_failed_character(
job_token: &job.job_token,
maybe_public_failure_reason: Some(reason),
internal_debugging_failure_reason: &internal_reason,
maybe_frontend_failure_category: None,
maybe_frontend_failure_category: Some(failure_category),
}).await {
error!(
"Error marking character job {} as failed: {:?}",
@@ -101,12 +101,12 @@ fn guess_failure_category(error_type: Option<&WebhookErrorType>) -> FrontendFail
match error_type {
Some(WebhookErrorType::ContentPolicyViolation) => FrontendFailureCategory::RuleBansUserContent,
Some(WebhookErrorType::FaceDetectionError) => FrontendFailureCategory::FaceNotDetected,
Some(WebhookErrorType::FileTooLarge) => FrontendFailureCategory::FilesizeTooLarge,
Some(WebhookErrorType::ImageTooLarge) => FrontendFailureCategory::ImageDimensionsTooLarge,
Some(WebhookErrorType::ImageTooSmall) => FrontendFailureCategory::ImageDimensionsTooSmall,
Some(WebhookErrorType::NoMediaGenerated)
| Some(WebhookErrorType::ImageTooSmall)
| Some(WebhookErrorType::ImageTooLarge)
| Some(WebhookErrorType::ImageLoadError)
| Some(WebhookErrorType::FileDownloadError)
| Some(WebhookErrorType::FileTooLarge) => FrontendFailureCategory::GenerationFailed,
| Some(WebhookErrorType::FileDownloadError) => FrontendFailureCategory::GenerationFailed,
_ => FrontendFailureCategory::GenerationFailed,
}
}