Handle ingestion failures
When sending usage events to Zenskar via API, it's important to understand how ingestion failures are handled, and how you can prevent data loss due to validation errors or network issues.
Why this matters
If a usage event does not show up in Zenskar, the assumption is often that it was lost by our system. In reality, ingestion can fail in two main ways:
1. Rejected by Zenskar due to validation errors
These are non-retriable failures. Zenskar received the event but rejected it due to issues like:
- Malformed JSON
- Invalid metric name
- Incorrect timestamp
In such cases, Zenskar responds with an HTTP 4xx
status code and a descriptive error message. If your system doesn't handle this response correctly, the event is lost.
2. Event never reached Zenskar
These are retriable failures. Events might not reach us due to:
- Network outages on your side
- Intermediate routing issues
- Zenskar service downtime
Since the event never reaches us, we can’t log it or notify you. If you don’t retry or store it, the event is lost permanently.
Recommended approach: implement a dead letter queue (DLQ)
DefinitionA dead letter queue (DLQ) is a mechanism to capture failed events so that they can be retried or examined later.
A DLQ is a holding area for failed events, either due to validation errors or delivery issues. This ensures no event is lost, even if initial ingestion fails.
sequenceDiagram participant Your system participant Zenskar API participant DLQ Your system->>Zenskar API: Send usage event alt Success Zenskar API-->>Your system: 200 OK else Validation error Zenskar API-->>Your system: 4xx error Your system->>DLQ: Store failed event else Network error Note right of Your system: No response received Your system->>DLQ: Store failed event end
Ways to implement a DLQ
You can implement a DLQ in many ways, depending on your system architecture and event volume. Here are some common approaches:
Method | Description |
---|---|
File-based logging | Write failed events to a local file. Easy to set up but less scalable. |
Database fallback | Store failed events in a database table for review and manual replay. |
Message queues (e.g. Kafka, RabbitMQ) | Send failed events to a dedicated DLQ topic or queue. Suitable for large-scale systems. |
Cloud-native DLQ (e.g. AWS SQS DLQ) | Use managed DLQ support with retry and failure handling built in. |
Error responses from Zenskar
Below is a sample of a valid event upload payload. Use this as a reference to ensure your requests are correctly structured:
[
{
"data": {
"campaign_id": "sample campaign_id 8",
"impressions": 74
},
"timestamp": "2025-06-28 23:44:47",
"customer_id": "c03"
}
]
When uploading usage events via the ingestion API, your request may be rejected with a 4xx
HTTP status code if there are issues with the payload. This guide outlines all possible 4xx
errors, explains their causes, and provides real examples to help you debug and resolve issues effectively.
HTTP 4xx error codes
404 Not Found
When:
- The request body is not valid JSON and cannot be parsed.
Example Response:
{
"error": "invalid character '}' looking for beginning of object key string"
}
413 Payload Too Large
When:
- The request body exceeds 1MB in size.
Example Response:
{
"error": "Payload too large"
}
422 Unprocessable Entity (validation errors)
When:
- The request body is valid JSON, but fails schema validation (missing keys, wrong types, unexpected keys, etc.).
Example Response:
{
"error": "Invalid type for key: impressions. Expected Int64, got string"
}
Validation error messages
The API validates your event payload against a schema. If validation fails, you will receive a 422
response with a descriptive error message. Below are the types of validation errors you may encounter:
Missing or unexpected keys
- Missing key: The payload is missing a required field.
{
"error": "Missing key: impressions"
}
- Unexpected key: The payload contains a field not defined in the schema.
{
"error": "Unexpected key in payload: extra_field"
}
Type mismatches
- String expected, got number:
{
"error": "Invalid type for key: campaign_id. Expected String, got float64"
}
- Int64 expected, got string:
{
"error": "Invalid type for key: impressions. Expected Int64, got string"
}
- Float64 expected, got string:
{
"error": "Invalid type for key: value. Expected Float64, got string"
}
- Boolean expected, got string:
{
"error": "Invalid type for key: is_active. Expected Bool, got string"
}
Date/time format errors
- Date32 expected, got wrong format:
{
"error": "Invalid type for key: start_date. Expected Date32, got string"
}
- DateTime64 expected, got wrong format:
{
"error": "Invalid type for key: timestamp. Expected Date32/DateTime64, got string"
}
UUID format errors
- UUID expected, got invalid string:
{
"error": "Invalid type for key: user_id. Expected UUID, got string"
}
Nested object errors
- Expected object, got something else:
{
"error": "Invalid type for key: data. Expected Object, got string"
}
- Nested validation error:
{
"error": "Invalid type for key: nested_field. Expected Int64, got string"
}
Example error responses
Here are some real-world examples of error responses you might see:
Example 1: Type mismatch
Request:
{
"data": {
"campaign_id": "sample_campaign_id_8",
"impressions": "74"
},
"timestamp": "2025-06-28 23:44:47",
"customer_id": "c03"
}
Response:
{
"error": "Invalid type for key: impressions. Expected Int64, got string"
}
Example 2: Missing key
Request:
{
"data": {
"campaign_id": "sample_campaign_id_8"
},
"timestamp": "2025-06-28 23:44:47",
"customer_id": "c03"
}
Response:
{
"error": "Missing key: impressions"
}
Example 3: Unexpected key
Request:
{
"data": {
"campaign_id": "sample_campaign_id_8",
"impressions": 74,
"extra_field": "not_allowed"
},
"timestamp": "2025-06-28 23:44:47",
"customer_id": "c03"
}
Response:
{
"error": "Unexpected key in payload: extra_field"
}
Best Practices
- Check the schema: Make sure your payload matches the expected schema for the usage event.
- Use correct types: Numbers should be numbers, not strings; dates should be in the correct format.
- Avoid extra fields: Only include fields defined in the schema.
- Keep payloads small: Stay under 1MB per request.
Summary Table
HTTP Status | When it Occurs | Example Error Message |
---|---|---|
404 | Invalid JSON | invalid character ... |
413 | Payload too large (>1MB) | Payload too large |
422 | Validation error (schema/type/format) | Invalid type for key: ... , Missing key: ... , etc. |
Updated about 20 hours ago