mirror of
https://github.com/coleam00/Archon.git
synced 2026-01-01 04:09:08 -05:00
feat: Implement comprehensive OpenAI error handling for Issue #362
Replace silent failures with clear, actionable error messages to eliminate 90-minute debugging sessions when OpenAI API quota is exhausted. ## Backend Enhancements - Add error sanitization preventing sensitive data exposure (API keys, URLs, tokens) - Add upfront API key validation before expensive operations (crawl, upload, refresh) - Implement fail-fast pattern in RAG service (no more empty results for API failures) - Add specific error handling for quota, rate limit, auth, and API errors - Add EmbeddingAuthenticationError exception with masked key prefix support ## Frontend Enhancements - Create enhanced error utilities with OpenAI-specific parsing - Build TanStack Query compatible API wrapper preserving ETag caching - Update knowledge service to use enhanced error handling - Enhance TanStack Query hooks with user-friendly error messages ## Security Features - Comprehensive regex sanitization (8 patterns) with ReDoS protection - Input validation and circular reference detection - Generic fallback messages for sensitive keywords - Bounded quantifiers to prevent regex DoS attacks ## User Experience - Clear error messages: "OpenAI API quota exhausted" - Actionable guidance: "Check your OpenAI billing dashboard and add credits" - Immediate error visibility (no more silent failures) - Appropriate error severity styling ## Architecture Compatibility - Full TanStack Query integration maintained - ETag caching and optimistic updates preserved - No performance regression (all existing tests pass) - Compatible with existing knowledge base architecture Resolves #362: Users no longer experience mysterious empty RAG results that require extensive debugging to identify OpenAI quota issues. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,7 @@ import { useActiveOperations } from "../progress/hooks";
|
||||
import { progressKeys } from "../progress/hooks/useProgressQueries";
|
||||
import type { ActiveOperation, ActiveOperationsResponse } from "../progress/types";
|
||||
import { knowledgeService } from "../services";
|
||||
import { getDisplayErrorMessage, type EnhancedError } from "../utils/errorHandler";
|
||||
import type {
|
||||
CrawlRequest,
|
||||
CrawlStartResponse,
|
||||
@@ -273,7 +274,10 @@ export function useCrawlUrl() {
|
||||
queryClient.setQueryData(progressKeys.list(), context.previousOperations);
|
||||
}
|
||||
|
||||
const errorMessage = error instanceof Error ? error.message : "Failed to start crawl";
|
||||
// Use enhanced error handling for better user experience
|
||||
const errorMessage = (error as EnhancedError)?.isOpenAIError
|
||||
? getDisplayErrorMessage(error as EnhancedError)
|
||||
: (error instanceof Error ? error.message : "Failed to start crawl");
|
||||
showToast(errorMessage, "error");
|
||||
},
|
||||
});
|
||||
@@ -449,8 +453,10 @@ export function useUploadDocument() {
|
||||
queryClient.setQueryData(progressKeys.list(), context.previousOperations);
|
||||
}
|
||||
|
||||
// Display the actual error message from backend
|
||||
const message = error instanceof Error ? error.message : "Failed to upload document";
|
||||
// Use enhanced error handling for better user experience
|
||||
const message = (error as EnhancedError)?.isOpenAIError
|
||||
? getDisplayErrorMessage(error as EnhancedError)
|
||||
: (error instanceof Error ? error.message : "Failed to upload document");
|
||||
showToast(message, "error");
|
||||
},
|
||||
});
|
||||
@@ -521,7 +527,10 @@ export function useDeleteKnowledgeItem() {
|
||||
queryClient.setQueryData(queryKey, data);
|
||||
}
|
||||
|
||||
const errorMessage = error instanceof Error ? error.message : "Failed to delete item";
|
||||
// Use enhanced error handling for better user experience
|
||||
const errorMessage = (error as EnhancedError)?.isOpenAIError
|
||||
? getDisplayErrorMessage(error as EnhancedError)
|
||||
: (error instanceof Error ? error.message : "Failed to delete item");
|
||||
showToast(errorMessage, "error");
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
@@ -568,7 +577,10 @@ export function useUpdateKnowledgeItem() {
|
||||
queryClient.setQueryData(knowledgeKeys.detail(variables.sourceId), context.previousItem);
|
||||
}
|
||||
|
||||
const errorMessage = error instanceof Error ? error.message : "Failed to update item";
|
||||
// Use enhanced error handling for better user experience
|
||||
const errorMessage = (error as EnhancedError)?.isOpenAIError
|
||||
? getDisplayErrorMessage(error as EnhancedError)
|
||||
: (error instanceof Error ? error.message : "Failed to update item");
|
||||
showToast(errorMessage, "error");
|
||||
},
|
||||
onSuccess: (_data, { sourceId }) => {
|
||||
@@ -604,7 +616,10 @@ export function useRefreshKnowledgeItem() {
|
||||
return data;
|
||||
},
|
||||
onError: (error) => {
|
||||
const errorMessage = error instanceof Error ? error.message : "Failed to refresh item";
|
||||
// Use enhanced error handling for better user experience
|
||||
const errorMessage = (error as EnhancedError)?.isOpenAIError
|
||||
? getDisplayErrorMessage(error as EnhancedError)
|
||||
: (error instanceof Error ? error.message : "Failed to refresh item");
|
||||
showToast(errorMessage, "error");
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user