mirror of
https://github.com/thecyberlearn/quantum-ai-v3.git
synced 2026-08-18 08:52:58 +00:00
✨ Fix webhook error handling with reliable error display
- API now properly detects N8N errors in 200 responses (OpenAI quota, etc.) - Returns 400 status with simple "Agent unavailable" message for webhook failures - Frontend shows errors in results container instead of disappearing toast notifications - Users now see clear, persistent error messages when agents fail - Keeps success toasts working, only fixes error display 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
a46b07e371
commit
838927f316
@ -102,18 +102,35 @@ def execute_agent(request):
|
||||
# Store webhook response
|
||||
execution.webhook_response = response.json() if response.headers.get('content-type', '').startswith('application/json') else {'raw': response.text}
|
||||
|
||||
if response.status_code == 200:
|
||||
# Check if response contains N8N error indicators
|
||||
has_error = False
|
||||
if response.status_code == 200 and execution.webhook_response:
|
||||
# Check for N8N error patterns
|
||||
if isinstance(execution.webhook_response, dict):
|
||||
if 'errorMessage' in execution.webhook_response or 'error' in execution.webhook_response:
|
||||
has_error = True
|
||||
|
||||
if response.status_code == 200 and not has_error:
|
||||
execution.status = 'completed'
|
||||
execution.output_data = execution.webhook_response
|
||||
else:
|
||||
execution.status = 'failed'
|
||||
execution.error_message = f"Webhook returned {response.status_code}: {response.text[:500]}"
|
||||
|
||||
execution.completed_at = timezone.now()
|
||||
execution.save()
|
||||
|
||||
serializer = AgentExecutionSerializer(execution)
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
else:
|
||||
execution.status = 'failed'
|
||||
if has_error:
|
||||
error_msg = execution.webhook_response.get('errorMessage', 'Webhook execution failed')
|
||||
execution.error_message = f"N8N Error: {error_msg[:500]}"
|
||||
else:
|
||||
execution.error_message = f"Webhook returned {response.status_code}: {response.text[:500]}"
|
||||
execution.completed_at = timezone.now()
|
||||
execution.save()
|
||||
|
||||
return Response({
|
||||
'error': 'Agent is temporarily unavailable. Please try again later.'
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
except requests.RequestException as e:
|
||||
execution.status = 'failed'
|
||||
|
||||
@ -57,7 +57,7 @@ class AgentsCore extends WorkflowsCore {
|
||||
} catch (error) {
|
||||
console.error('Form submission error:', error);
|
||||
this.constructor.hideProcessing();
|
||||
this.constructor.showToast('❌ Connection error. Please try again.', 'error');
|
||||
this.showErrorMessage('❌ Agent is temporarily unavailable. Please try again later.');
|
||||
this.resetSubmitButton();
|
||||
}
|
||||
}
|
||||
@ -84,7 +84,7 @@ class AgentsCore extends WorkflowsCore {
|
||||
} catch (error) {
|
||||
console.error('Agent execution error:', error);
|
||||
this.constructor.hideProcessing();
|
||||
this.constructor.showToast(`❌ ${error.message}`, 'error');
|
||||
this.showErrorMessage('❌ Agent is temporarily unavailable. Please try again later.');
|
||||
this.resetSubmitButton();
|
||||
}
|
||||
}
|
||||
@ -545,6 +545,36 @@ class AgentsCore extends WorkflowsCore {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show error message in results container
|
||||
*/
|
||||
showErrorMessage(message) {
|
||||
const resultsContainer = document.getElementById('resultsContainer');
|
||||
const resultsContent = document.getElementById('resultsContent');
|
||||
|
||||
if (resultsContainer && resultsContent) {
|
||||
resultsContent.innerHTML = `
|
||||
<div style="
|
||||
background: #fee2e2;
|
||||
border: 1px solid #fecaca;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
color: #dc2626;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
margin: 20px 0;
|
||||
">
|
||||
${message}
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Show results container
|
||||
resultsContainer.style.display = 'block';
|
||||
resultsContainer.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset submit button to original state
|
||||
*/
|
||||
|
||||
@ -32,8 +32,9 @@ class WorkflowsCore {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
z-index: 10000;
|
||||
z-index: 99999;
|
||||
max-width: 400px;
|
||||
pointer-events: none;
|
||||
`;
|
||||
|
||||
// Safely append to body
|
||||
@ -61,6 +62,9 @@ class WorkflowsCore {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
animation: slideIn 0.3s ease-out;
|
||||
pointer-events: auto;
|
||||
position: relative;
|
||||
z-index: 100000;
|
||||
`;
|
||||
|
||||
// Add icon and message
|
||||
@ -94,12 +98,13 @@ class WorkflowsCore {
|
||||
|
||||
toastContainer.appendChild(toast);
|
||||
|
||||
// Auto-remove after 5 seconds
|
||||
// Auto-remove after longer time for errors
|
||||
const timeout = type === 'error' ? 8000 : 5000; // 8 seconds for errors, 5 for others
|
||||
setTimeout(() => {
|
||||
if (toast.parentElement) {
|
||||
toast.remove();
|
||||
}
|
||||
}, 5000);
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Loading…
Reference in New Issue
Block a user