-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Fix #362: Surface OpenAI authentication errors as HTTP 401 #371
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from 31 commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
96c2875
Fix OpenAI quota exhaustion error handling in RAG queries
leex279 2c16ed9
Remove unused variable to fix linting
leex279 f23faea
Add comprehensive frontend error handling for OpenAI API errors
leex279 c3a9548
Fix #362: Enhance OpenAI API error handling with sanitization and retβ¦
leex279 6652873
Implement code review findings: Security and performance improvements
leex279 3c0fc55
Fix OpenAI API key cache invalidation regression
leex279 5fbe8fb
Merge latest main into bugfix-issue-362 - Keep OpenAI error handling β¦
leex279 0a8bea6
Add comprehensive OpenAI AuthenticationError handling
leex279 f770675
Fix crawl success reporting when embeddings fail
leex279 c3cf1ee
RAG: surface OpenAI auth errors as 401; fix single-vector embedding cβ¦
2c3b8ef
PR #521: address CodeRabbit review β consistent 401 payload; mask keyβ¦
46a98da
Merge PR 521: Fix authentication error handling in RAG
leex279 0fce8a5
Add upfront OpenAI API key validation to prevent wasted crawling
leex279 3337b90
Fix UI error display: restore enhanced error handling in KnowledgeBasβ¦
leex279 de8aa8a
fix: Address CodeRabbit review comments
leex279 2ffe1ac
Merge latest main changes into OpenAI error handling branch
leex279 26d0588
fix: Improve UI error display for OpenAI authentication errors
leex279 afe8c56
fix: Add clear 401 status code to authentication error message
leex279 39451b7
debug: Add detailed logging to diagnose error parsing issue
leex279 071840a
fix: Use enhanced UI error messages directly in error parsing
leex279 71e83dd
fix: Address CodeRabbit review suggestions for error handling
leex279 3e09eba
fix: Resolve backend test failures
leex279 99375c6
fix: Update tests for fail-fast behavior and fix storage mocks
leex279 1f382e5
fix: Add comprehensive mocking to prevent real API calls in tests
leex279 7c8d3e4
fix: Correct chunk count in document storage test
leex279 5ef7c2f
fix: Remove non-existent EmbeddingResult import causing test collectiβ¦
leex279 e1aec98
fix: Update tests to expect masked API key prefix
leex279 65c4363
fix: Allow test-specific mocking by removing autouse create_embeddingβ¦
leex279 9cc7023
fix: Mock search_documents directly to test error handling pipeline
leex279 efeaaab
Delete OPENAI_ERROR_HANDLING.md
leex279 7a3775a
fix: Address critical and warning issues from code review
leex279 ff16882
Merge origin/main into bugfix-issue-362
leex279 e5235e6
Fix missing import for enhanced error handling in KnowledgeBasePage
leex279 57ee971
Add debug logging to frontend error parsing
leex279 5562605
Merge remote-tracking branch 'origin/main' into bugfix-issue-362
leex279 63c51e3
fix: Address ReDoS vulnerability in regex patterns
leex279 80e0cff
fix: Optimize isSafeObject performance in error handler
leex279 faf5ece
fix: Add frontend sanitization for sensitive data in error messages
leex279 9c85295
fix: Sanitize string error messages to prevent sensitive data leakage
leex279 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| /** | ||
| * Basic Alert component for error display | ||
| * | ||
| * Provides consistent styling for alerts throughout the application. | ||
| */ | ||
|
|
||
| import React from 'react'; | ||
|
|
||
| interface AlertProps { | ||
| children: React.ReactNode; | ||
| variant?: 'default' | 'destructive'; | ||
| className?: string; | ||
| } | ||
|
|
||
| export const Alert: React.FC<AlertProps> = ({ | ||
| children, | ||
| variant = 'default', | ||
| className = '' | ||
| }) => { | ||
| const baseClasses = 'p-4 border rounded-lg'; | ||
| const variantClasses = variant === 'destructive' | ||
| ? 'border-red-300 bg-red-50 text-red-800' | ||
| : 'border-blue-300 bg-blue-50 text-blue-800'; | ||
|
|
||
| return ( | ||
| <div className={`${baseClasses} ${variantClasses} ${className}`}> | ||
| {children} | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| interface AlertDescriptionProps { | ||
| children: React.ReactNode; | ||
| className?: string; | ||
| } | ||
|
|
||
| export const AlertDescription: React.FC<AlertDescriptionProps> = ({ | ||
| children, | ||
| className = '' | ||
| }) => { | ||
| return ( | ||
| <div className={className}> | ||
| {children} | ||
| </div> | ||
| ); | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,162 @@ | ||
| /** | ||
| * Enhanced error alert component for displaying OpenAI API errors | ||
| * | ||
| * Provides specialized UI feedback for different error types including | ||
| * quota exhaustion, rate limiting, and API errors. | ||
| * | ||
| * Related to GitHub issue #362 - improves user experience by showing | ||
| * clear, actionable error messages instead of generic failures. | ||
| */ | ||
|
|
||
| import React from 'react'; | ||
| import { Alert, AlertDescription } from './Alert'; | ||
| import { EnhancedError, getDisplayErrorMessage, getErrorSeverity, getErrorAction } from '../../services/knowledgeBaseErrorHandler'; | ||
|
|
||
| interface ErrorAlertProps { | ||
| error: EnhancedError | null; | ||
| onDismiss?: () => void; | ||
| className?: string; | ||
| } | ||
|
|
||
| /** | ||
| * Validate error object structure and properties | ||
| */ | ||
| function isValidError(error: any): error is EnhancedError { | ||
| if (!error || typeof error !== 'object') return false; | ||
|
|
||
| // Check that it has basic Error properties | ||
| if (typeof error.message !== 'string') return false; | ||
|
|
||
| // If it claims to be an OpenAI error, validate the structure | ||
| if (error.isOpenAIError === true) { | ||
| if (!error.errorDetails || typeof error.errorDetails !== 'object') return false; | ||
|
|
||
| const { error_type, message, error: errorField } = error.errorDetails; | ||
| if (typeof error_type !== 'string' || typeof message !== 'string') return false; | ||
| } | ||
|
|
||
| // If statusCode is present, it should be a number | ||
| if (error.statusCode !== undefined && typeof error.statusCode !== 'number') return false; | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| export const ErrorAlert: React.FC<ErrorAlertProps> = ({ error, onDismiss, className = '' }) => { | ||
| if (!error) return null; | ||
|
|
||
| // Validate error object structure | ||
| if (!isValidError(error)) { | ||
| console.warn('Invalid error object passed to ErrorAlert:', error); | ||
| // Create a fallback error object | ||
| const fallbackError: EnhancedError = Object.assign(new Error('Invalid error object received'), { | ||
| errorDetails: { | ||
| error: 'validation_error', | ||
| message: 'An error occurred but the error details could not be parsed properly.', | ||
| error_type: 'api_error' as const | ||
| } | ||
| }); | ||
| error = fallbackError; | ||
| } | ||
|
|
||
| const severity = getErrorSeverity(error); | ||
| const displayMessage = getDisplayErrorMessage(error); | ||
| const suggestedAction = getErrorAction(error); | ||
|
|
||
| // Determine alert styling based on severity | ||
| const alertVariant = severity === 'error' ? 'destructive' : 'default'; | ||
|
|
||
| // Special styling for OpenAI errors | ||
| const isOpenAIError = error.isOpenAIError; | ||
|
|
||
| return ( | ||
| <Alert variant={alertVariant} className={`mb-4 ${className}`}> | ||
| <div className="flex items-start justify-between"> | ||
| <div className="flex-1"> | ||
| {/* Error icon based on type */} | ||
| <div className="flex items-center gap-2 mb-2"> | ||
| {isOpenAIError ? ( | ||
| <span className="text-lg">β οΈ</span> | ||
| ) : ( | ||
| <span className="text-lg">β</span> | ||
| )} | ||
| <span className="font-semibold"> | ||
| {isOpenAIError ? 'OpenAI API Error' : 'Error'} | ||
| </span> | ||
| </div> | ||
|
|
||
| {/* Main error message */} | ||
| <AlertDescription className="text-sm mb-2"> | ||
| {displayMessage} | ||
| </AlertDescription> | ||
|
|
||
| {/* Suggested action for OpenAI errors */} | ||
| {suggestedAction && ( | ||
| <div className="mt-2 p-2 bg-blue-50 border-l-4 border-blue-400 rounded-r"> | ||
| <p className="text-sm font-medium text-blue-800"> | ||
| π‘ Suggested action: | ||
| </p> | ||
| <p className="text-sm text-blue-700 mt-1"> | ||
| {suggestedAction} | ||
| </p> | ||
| </div> | ||
| )} | ||
|
|
||
| {/* Token usage info for quota errors */} | ||
| {error.errorDetails?.tokens_used && ( | ||
| <div className="mt-2 text-xs text-gray-600"> | ||
| Tokens used: {error.errorDetails.tokens_used.toLocaleString()} | ||
| </div> | ||
| )} | ||
| </div> | ||
|
|
||
| {/* Dismiss button */} | ||
| {onDismiss && ( | ||
| <button | ||
| onClick={onDismiss} | ||
| className="ml-4 text-gray-400 hover:text-gray-600 focus:outline-none" | ||
| aria-label="Dismiss error" | ||
| > | ||
| <span className="text-lg">Γ</span> | ||
| </button> | ||
| )} | ||
| </div> | ||
| </Alert> | ||
| ); | ||
| }; | ||
|
|
||
| /** | ||
| * Hook for handling knowledge base operation errors | ||
| * | ||
| * Usage example: | ||
| * ```tsx | ||
| * const { error, setError, clearError } = useErrorHandler(); | ||
| * | ||
| * const handleSearch = async () => { | ||
| * try { | ||
| * await knowledgeBaseService.searchKnowledgeBase(query); | ||
| * } catch (err) { | ||
| * setError(err as EnhancedError); | ||
| * } | ||
| * }; | ||
| * | ||
| * return ( | ||
| * <> | ||
| * <ErrorAlert error={error} onDismiss={clearError} /> | ||
| * <YourComponentContent /> | ||
| * </> | ||
| * ); | ||
| * ``` | ||
| */ | ||
| export function useErrorHandler() { | ||
| const [error, setError] = React.useState<EnhancedError | null>(null); | ||
|
|
||
| const clearError = React.useCallback(() => { | ||
| setError(null); | ||
| }, []); | ||
|
|
||
| return { | ||
| error, | ||
| setError, | ||
| clearError | ||
| }; | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,7 @@ import { KnowledgeItemCard } from '../components/knowledge-base/KnowledgeItemCar | |
| import { GroupedKnowledgeItemCard } from '../components/knowledge-base/GroupedKnowledgeItemCard'; | ||
| import { KnowledgeGridSkeleton, KnowledgeTableSkeleton } from '../components/knowledge-base/KnowledgeItemSkeleton'; | ||
| import { GroupCreationModal } from '../components/knowledge-base/GroupCreationModal'; | ||
| import { parseKnowledgeBaseError, getDisplayErrorMessage, getErrorAction, EnhancedError } from '../services/knowledgeBaseErrorHandler'; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π οΈ Refactor suggestion Map 401/auth errors to actionable UI + small import nit
Example adjustments in knowledgeBaseErrorHandler.ts (outside this file): // getDisplayErrorMessage
case 'authentication':
case 'auth_error':
case 'invalid_api_key':
return 'OpenAI authentication failed. Please verify your API key or organization/project configuration.';
// HTTP codes:
case 401:
return 'Authentication failed (401). Check your API key configuration.';
// getErrorAction
case 'authentication':
case 'auth_error':
case 'invalid_api_key':
return 'Verify your OpenAI API key in Settings';
// Fallback for HTTP 401
if (error.statusCode === 401) return 'Verify your OpenAI API key in Settings';π€ Prompt for AI Agents |
||
|
|
||
| const extractDomain = (url: string): string => { | ||
| try { | ||
|
|
@@ -92,7 +93,11 @@ export const KnowledgeBasePage = () => { | |
| setTotalItems(response.total); | ||
| } catch (error) { | ||
| console.error('Failed to load knowledge items:', error); | ||
| showToast('Failed to load knowledge items', 'error'); | ||
|
|
||
| // Parse the error using enhanced error handler | ||
| const enhancedError = parseKnowledgeBaseError(error); | ||
| const displayMessage = getDisplayErrorMessage(enhancedError); | ||
| showToast(displayMessage, 'error'); | ||
| setKnowledgeItems([]); | ||
| } finally { | ||
| setLoading(false); | ||
|
|
@@ -498,7 +503,17 @@ export const KnowledgeBasePage = () => { | |
| } | ||
| } catch (error) { | ||
| console.error('Failed to refresh knowledge item:', error); | ||
| showToast('Failed to refresh knowledge item', 'error'); | ||
|
|
||
| // Parse the error using enhanced error handler | ||
| const enhancedError = parseKnowledgeBaseError(error); | ||
| const displayMessage = getDisplayErrorMessage(enhancedError); | ||
| const suggestedAction = getErrorAction(enhancedError); | ||
|
|
||
| const fullMessage = suggestedAction | ||
| ? `${displayMessage} ${suggestedAction}` | ||
| : displayMessage; | ||
|
|
||
| showToast(fullMessage, 'error'); | ||
| } | ||
| }; | ||
|
|
||
|
|
@@ -737,7 +752,17 @@ export const KnowledgeBasePage = () => { | |
| } | ||
| } catch (error) { | ||
| console.error('Failed to retry:', error); | ||
| showToast(`Retry failed: ${error instanceof Error ? error.message : 'Unknown error'}`, 'error'); | ||
|
|
||
| // Parse the error using enhanced error handler | ||
| const enhancedError = parseKnowledgeBaseError(error); | ||
| const displayMessage = getDisplayErrorMessage(enhancedError); | ||
| const suggestedAction = getErrorAction(enhancedError); | ||
|
|
||
| const fullMessage = suggestedAction | ||
| ? `Retry failed: ${displayMessage} ${suggestedAction}` | ||
| : `Retry failed: ${displayMessage}`; | ||
|
|
||
| showToast(fullMessage, 'error'); | ||
| } | ||
| }; | ||
|
|
||
|
|
@@ -1384,7 +1409,18 @@ const AddKnowledgeModal = ({ | |
| } | ||
| } catch (error) { | ||
| console.error('Failed to add knowledge:', error); | ||
| showToast('Failed to add knowledge source', 'error'); | ||
|
|
||
| // Parse the error using the enhanced error handler | ||
| const enhancedError = parseKnowledgeBaseError(error); | ||
| const displayMessage = getDisplayErrorMessage(enhancedError); | ||
| const suggestedAction = getErrorAction(enhancedError); | ||
|
|
||
| // Show enhanced error message with action if available | ||
| const fullMessage = suggestedAction | ||
| ? `${displayMessage} ${suggestedAction}` | ||
| : displayMessage; | ||
|
|
||
| showToast(fullMessage, 'error'); | ||
| } finally { | ||
| setLoading(false); | ||
| } | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.