From 883d9afa2d634d9677bb2bff85584bc7c74214cb Mon Sep 17 00:00:00 2001 From: Peter Foster Date: Thu, 22 Jan 2026 19:54:17 +0000 Subject: [PATCH] feat: Show user-friendly error messages for failed CV checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Store specific error message in ProcessingStage field on failure - Display meaningful messages like "No useful data could be extracted" - Handle common failure scenarios: scanned images, API limits, encrypted files 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../Jobs/ProcessCVCheckJob.cs | 37 +++++++++++++++++++ src/RealCV.Web/Components/Pages/Report.razor | 2 +- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/RealCV.Infrastructure/Jobs/ProcessCVCheckJob.cs b/src/RealCV.Infrastructure/Jobs/ProcessCVCheckJob.cs index 7eebb60..ce01638 100644 --- a/src/RealCV.Infrastructure/Jobs/ProcessCVCheckJob.cs +++ b/src/RealCV.Infrastructure/Jobs/ProcessCVCheckJob.cs @@ -292,6 +292,8 @@ public sealed class ProcessCVCheckJob try { cvCheck.Status = CheckStatus.Failed; + // Store a user-friendly error message + cvCheck.ProcessingStage = GetUserFriendlyErrorMessage(ex); // Use CancellationToken.None to ensure failure status is saved even if original token is cancelled await _dbContext.SaveChangesAsync(CancellationToken.None); } @@ -1424,4 +1426,39 @@ public sealed class ProcessCVCheckJob obj.FlagType?.ToUpperInvariant() ?? ""); } } + + /// + /// Returns a user-friendly error message based on the exception type. + /// + private static string GetUserFriendlyErrorMessage(Exception ex) + { + // Check for specific error patterns + var message = ex.Message; + + if (message.Contains("no extractable data", StringComparison.OrdinalIgnoreCase) || + message.Contains("Could not extract any employment", StringComparison.OrdinalIgnoreCase)) + { + return "No useful data could be extracted from this CV. The file may be a scanned image or in an unsupported format."; + } + + if (message.Contains("API usage limits", StringComparison.OrdinalIgnoreCase) || + message.Contains("rate limit", StringComparison.OrdinalIgnoreCase)) + { + return "Service temporarily unavailable. Please try again in a few minutes."; + } + + if (message.Contains("Could not extract text", StringComparison.OrdinalIgnoreCase)) + { + return "Could not read the CV file. Please ensure it's a valid PDF or DOCX document."; + } + + if (message.Contains("password", StringComparison.OrdinalIgnoreCase) || + message.Contains("encrypted", StringComparison.OrdinalIgnoreCase)) + { + return "This CV appears to be password-protected. Please upload an unprotected version."; + } + + // Default message + return "An error occurred while processing your CV. Please try uploading again."; + } } diff --git a/src/RealCV.Web/Components/Pages/Report.razor b/src/RealCV.Web/Components/Pages/Report.razor index 63f963e..eb5d943 100644 --- a/src/RealCV.Web/Components/Pages/Report.razor +++ b/src/RealCV.Web/Components/Pages/Report.razor @@ -74,7 +74,7 @@

Processing Failed

-

We encountered an error processing your CV. Please try uploading again.

+

@(!string.IsNullOrEmpty(_check.ProcessingStage) ? _check.ProcessingStage : "We encountered an error processing your CV. Please try uploading again.")

}