Error Handling¶
ScamShield AI is designed to always return a usable response, even when errors occur. This is critical for maintaining scammer engagement -- a failed response means the scammer moves on to a real victim.
Error Response Format¶
| Field | Type | Description |
|---|---|---|
status |
"error" |
Indicates an error occurred. |
reply |
string |
Empty string for error responses. |
error |
string |
Human-readable error description. |
HTTP Status Codes¶
| Code | Meaning | When |
|---|---|---|
200 |
Success | Request processed successfully. Also returned for internal errors with a stalling reply (see Graceful Degradation). |
401 |
Unauthorized | Missing or invalid x-api-key header. |
400 |
Bad Request | Request body fails Pydantic validation. |
405 |
Method Not Allowed | Request method is not POST (or OPTIONS for CORS). |
429 |
Rate Limited | Session has exceeded rate limits. |
500 |
Internal Error | Unrecoverable server error. |
Graceful Degradation¶
ScamShield AI prioritizes engagement continuity. When an internal error occurs (e.g., Gemini API failure, Firestore timeout), the endpoint returns HTTP 200 with a stalling reply instead of an error:
{
"status": "success",
"reply": "Ek minute, network slow hai. Thodi der mein message karta hoon.",
"sessionId": "session-abc-123",
"scamDetected": false,
"extractedIntelligence": {
"bankAccounts": [], "upiIds": [], "phishingLinks": [],
"phoneNumbers": [], "emailAddresses": [], "suspiciousKeywords": [],
"ifscCodes": [], "cryptoWallets": [], "aadhaarNumbers": [],
"panNumbers": [], "amounts": [], "caseIds": [],
"policyNumbers": [], "orderNumbers": []
},
"engagementMetrics": {
"engagementDurationSeconds": 0.0,
"totalMessagesExchanged": 0
},
"agentNotes": "Error fallback: Gemini API timeout after 30s"
}
This behavior ensures:
- The evaluator does not score the turn as a complete failure
- The scammer receives a plausible stalling message
- The next turn can recover with a fresh request
Authentication Errors¶
Missing API Key¶
curl -X POST .../guvi_honeypot \
-H "Content-Type: application/json" \
-d '{"sessionId": "test", ...}'
Response (HTTP 401):
Invalid API Key¶
curl -X POST .../guvi_honeypot \
-H "Content-Type: application/json" \
-H "x-api-key: wrong-key" \
-d '{"sessionId": "test", ...}'
Response (HTTP 401):
Dev Mode (No Key Configured)¶
When SCAMSHIELD_API_KEY is not set and the function is running locally (outside Cloud Run/Cloud Functions), all requests are allowed regardless of the x-api-key header. In production (K_SERVICE is set), requests are denied.
Validation Errors¶
Request body validation is handled by Pydantic. If the request body is malformed, the error is caught and a stalling reply is returned (HTTP 200, graceful degradation).
Missing Required Fields¶
If sessionId, message, or metadata is missing:
// Request (missing metadata)
{
"sessionId": "test-001",
"message": { "sender": "scammer", "text": "Hello", "timestamp": 1700000000 }
}
// Response (HTTP 200, graceful degradation)
{
"status": "success",
"reply": "Ek minute, network slow hai. Thodi der mein message karta hoon.",
"agentNotes": "Error fallback: 1 validation error for GuviRequest..."
}
Invalid Timestamp¶
// Request
{
"sessionId": "test-001",
"message": {
"sender": "scammer",
"text": "Hello",
"timestamp": -1
},
"metadata": { "channel": "SMS", "language": "English", "locale": "IN" }
}
// Response (HTTP 200, graceful degradation)
{
"status": "success",
"reply": "Ek minute, network slow hai. Thodi der mein message karta hoon.",
"agentNotes": "Error fallback: Timestamp must be non-negative, got: -1.0"
}
Rate Limiting¶
Rate limiting uses Firestore atomic counters per session.
Limits¶
| Limit | Value | Scope |
|---|---|---|
| Total messages | 100 | Per session (lifetime) |
| Messages per minute | 10 | Per session (sliding window) |
Rate-Limited Response¶
When a session exceeds the limit, the endpoint returns HTTP 200 with a stalling reply:
{
"status": "success",
"reply": "Ek minute ruko beta, bahut zyada messages aa rahe hain. Thoda der mein baat karte hain.",
"sessionId": "session-abc-123",
"scamDetected": false,
"extractedIntelligence": {
"bankAccounts": [], "upiIds": [], "phishingLinks": [],
"phoneNumbers": [], "emailAddresses": [], "suspiciousKeywords": [],
"ifscCodes": [], "cryptoWallets": [], "aadhaarNumbers": [],
"panNumbers": [], "amounts": [], "caseIds": [],
"policyNumbers": [], "orderNumbers": []
},
"engagementMetrics": {
"engagementDurationSeconds": 0.0,
"totalMessagesExchanged": 0
},
"agentNotes": "Rate limited — stalling scammer"
}
Rate Limiter Failure¶
If the rate limiter itself fails (e.g., Firestore is temporarily unavailable), the request is allowed to proceed. This is a deliberate design choice -- it is better to process a message than to block it when the rate limiter state is unknown.
CORS¶
The endpoint supports CORS preflight:
OPTIONSrequests return204withAccess-Control-Allow-Origin: *- All responses include
Access-Control-Allow-Origin: * - Allowed methods:
POST,OPTIONS - Allowed headers:
Content-Type,x-api-key
Error Codes Summary¶
| Scenario | HTTP Code | status |
Has reply? |
|---|---|---|---|
| Successful processing | 200 | "success" |
Yes (persona response) |
| Internal error (graceful) | 200 | "success" |
Yes (stalling message) |
| Rate limited | 200 | "success" |
Yes (stalling message) |
| Invalid API key | 401 | "error" |
No |
| Wrong HTTP method | 405 | "error" |
No |
| Unrecoverable error | 500 | "error" |
No |