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
|
# Store webhook response
|
||||||
execution.webhook_response = response.json() if response.headers.get('content-type', '').startswith('application/json') else {'raw': response.text}
|
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.status = 'completed'
|
||||||
execution.output_data = execution.webhook_response
|
execution.output_data = execution.webhook_response
|
||||||
|
execution.completed_at = timezone.now()
|
||||||
|
execution.save()
|
||||||
|
|
||||||
|
serializer = AgentExecutionSerializer(execution)
|
||||||
|
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||||
else:
|
else:
|
||||||
execution.status = 'failed'
|
execution.status = 'failed'
|
||||||
execution.error_message = f"Webhook returned {response.status_code}: {response.text[:500]}"
|
if has_error:
|
||||||
|
error_msg = execution.webhook_response.get('errorMessage', 'Webhook execution failed')
|
||||||
execution.completed_at = timezone.now()
|
execution.error_message = f"N8N Error: {error_msg[:500]}"
|
||||||
execution.save()
|
else:
|
||||||
|
execution.error_message = f"Webhook returned {response.status_code}: {response.text[:500]}"
|
||||||
serializer = AgentExecutionSerializer(execution)
|
execution.completed_at = timezone.now()
|
||||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
execution.save()
|
||||||
|
|
||||||
|
return Response({
|
||||||
|
'error': 'Agent is temporarily unavailable. Please try again later.'
|
||||||
|
}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
execution.status = 'failed'
|
execution.status = 'failed'
|
||||||
|
|||||||
@ -57,7 +57,7 @@ class AgentsCore extends WorkflowsCore {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Form submission error:', error);
|
console.error('Form submission error:', error);
|
||||||
this.constructor.hideProcessing();
|
this.constructor.hideProcessing();
|
||||||
this.constructor.showToast('❌ Connection error. Please try again.', 'error');
|
this.showErrorMessage('❌ Agent is temporarily unavailable. Please try again later.');
|
||||||
this.resetSubmitButton();
|
this.resetSubmitButton();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,7 +84,7 @@ class AgentsCore extends WorkflowsCore {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Agent execution error:', error);
|
console.error('Agent execution error:', error);
|
||||||
this.constructor.hideProcessing();
|
this.constructor.hideProcessing();
|
||||||
this.constructor.showToast(`❌ ${error.message}`, 'error');
|
this.showErrorMessage('❌ Agent is temporarily unavailable. Please try again later.');
|
||||||
this.resetSubmitButton();
|
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
|
* Reset submit button to original state
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -32,8 +32,9 @@ class WorkflowsCore {
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
top: 20px;
|
top: 20px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
z-index: 10000;
|
z-index: 99999;
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
|
pointer-events: none;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// Safely append to body
|
// Safely append to body
|
||||||
@ -61,6 +62,9 @@ class WorkflowsCore {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
animation: slideIn 0.3s ease-out;
|
animation: slideIn 0.3s ease-out;
|
||||||
|
pointer-events: auto;
|
||||||
|
position: relative;
|
||||||
|
z-index: 100000;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// Add icon and message
|
// Add icon and message
|
||||||
@ -94,12 +98,13 @@ class WorkflowsCore {
|
|||||||
|
|
||||||
toastContainer.appendChild(toast);
|
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(() => {
|
setTimeout(() => {
|
||||||
if (toast.parentElement) {
|
if (toast.parentElement) {
|
||||||
toast.remove();
|
toast.remove();
|
||||||
}
|
}
|
||||||
}, 5000);
|
}, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user