Appearance
Error Handling
DialogueDB uses standardized error responses to help you handle failures gracefully and build robust applications.
Error Response Format
All error responses follow a consistent structure:
json
{
"error": {
"code": "DIALOGUE_NOT_FOUND",
"message": "Dialogue 'dlg_abc123' not found",
"type": "not_found",
"details": [
{
"field": "id",
"code": "NOT_FOUND",
"message": "Resource does not exist"
}
],
"requestId": "req_xyz789",
"timestamp": "2025-11-06T21:34:21.117Z"
}
}Error Object Fields
| Field | Type | Description |
|---|---|---|
code | string | Machine-readable error code (e.g., DIALOGUE_NOT_FOUND) |
message | string | Human-readable error description |
type | string | Error category: validation_error, not_found, conflict, rate_limit, server |
details | array | Optional field-level validation errors |
requestId | string | Unique request identifier for debugging |
timestamp | string | ISO 8601 timestamp when the error occurred |
HTTP Status Codes
DialogueDB uses standard HTTP status codes to indicate the type of error:
| Status | Meaning | When Used |
|---|---|---|
| 400 | Bad Request | Validation errors, missing required fields, invalid input |
| 401 | Unauthorized | Missing or invalid authentication token |
| 404 | Not Found | Resource (dialogue, message, project) does not exist |
| 409 | Conflict | Resource conflict (e.g., dialogue immutability violation) |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Unexpected server error |
Error Types
Validation Errors (400)
Returned when request data is invalid or missing required fields.
Example:
json
{
"error": {
"code": "MISSING_PARAMETER",
"message": "Missing required parameter: id",
"type": "validation_error",
"details": [
{
"field": "id",
"code": "REQUIRED",
"message": "Dialogue ID is required"
}
],
"requestId": "req_123",
"timestamp": "2025-11-06T21:34:21Z"
}
}Common validation error codes:
MISSING_PARAMETER- Required parameter not providedINVALID_PARAMETER- Parameter format is invalidMESSAGE_CONTENT_EMPTY- Message content cannot be emptyMESSAGE_TOO_LARGE- Message exceeds size limitTOO_MANY_MESSAGES- Exceeds message limit on creationINVALID_MESSAGE_ARRAY- Messages must be an arrayINVALID_ACTION- Unsupported action specified
Not Found Errors (404)
Returned when a requested resource does not exist.
Example:
json
{
"error": {
"code": "DIALOGUE_NOT_FOUND",
"message": "Dialogue 'dlg_abc123' not found",
"type": "not_found",
"requestId": "req_456",
"timestamp": "2025-11-06T21:34:21Z"
}
}Common not found error codes:
DIALOGUE_NOT_FOUND- Dialogue does not existMESSAGE_NOT_FOUND- Message does not existPROJECT_NOT_FOUND- Project does not existPARENT_DIALOGUE_NOT_FOUND- Parent dialogue for thread not found
Conflict Errors (409)
Returned when operation conflicts with resource state.
Example:
json
{
"error": {
"code": "DIALOGUE_IMMUTABLE",
"message": "Cannot delete message: dialogues are immutable in this project",
"type": "conflict",
"requestId": "req_789",
"timestamp": "2025-11-06T21:34:21Z"
}
}Common conflict error codes:
DIALOGUE_IMMUTABLE- Operation not allowed on immutable dialogueDUPLICATE_ID- Resource with this ID already existsRESOURCE_CONFLICT- Operation conflicts with resource state
Rate Limit Errors (429)
Returned when API rate limits are exceeded.
Example:
json
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Please try again later.",
"type": "rate_limit",
"requestId": "req_999",
"timestamp": "2025-11-06T21:34:21Z"
}
}Response headers:
http
X-RateLimit-Limit: 50
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1640000060
Retry-After: 60Server Errors (500)
Returned for unexpected server-side errors.
Example:
json
{
"error": {
"code": "INTERNAL_ERROR",
"message": "An internal error occurred while processing your request",
"type": "server",
"requestId": "req_555",
"timestamp": "2025-11-06T21:34:21Z"
}
}Error Code Reference
Validation Errors (400)
| Code | HTTP Status | Description |
|---|---|---|
MISSING_PARAMETER | 400 | Required parameter missing from request |
INVALID_PARAMETER | 400 | Parameter format or value is invalid |
INVALID_INPUT | 400 | Input validation failed |
VALIDATION_ERROR | 400 | General validation error |
MESSAGE_CONTENT_EMPTY | 400 | Message content cannot be empty |
MESSAGE_TOO_LARGE | 400 | Message exceeds maximum size (1MB uncompressed) |
TOO_MANY_MESSAGES | 400 | Exceeds message limit on creation |
INVALID_MESSAGE_ARRAY | 400 | Messages parameter must be an array |
EMPTY_MESSAGE_ARRAY | 400 | Messages array cannot be empty |
INVALID_ACTION | 400 | Unsupported action specified |
SEARCH_QUERY_TOO_SHORT | 400 | Search query must be at least 3 characters |
Not Found Errors (404)
| Code | HTTP Status | Description |
|---|---|---|
DIALOGUE_NOT_FOUND | 404 | Dialogue with specified ID not found |
MESSAGE_NOT_FOUND | 404 | Message with specified ID not found |
PROJECT_NOT_FOUND | 404 | Project does not exist |
PARENT_DIALOGUE_NOT_FOUND | 404 | Parent dialogue for thread not found |
RESOURCE_NOT_FOUND | 404 | Generic resource not found |
Conflict Errors (409)
| Code | HTTP Status | Description |
|---|---|---|
DIALOGUE_IMMUTABLE | 409 | Operation not allowed on immutable dialogue |
DUPLICATE_ID | 409 | Resource with this ID already exists |
RESOURCE_CONFLICT | 409 | Operation conflicts with resource state |
Rate Limit & Plan Limit Errors (429)
| Code | HTTP Status | Description |
|---|---|---|
RATE_LIMIT_EXCEEDED | 429 | Too many requests - retry after delay |
PLAN_LIMIT_EXCEEDED | 429 | Plan quota exceeded - upgrade to continue writing. Existing data remains accessible; only new writes are blocked. No overage charges. |
Server Errors (500)
| Code | HTTP Status | Description |
|---|---|---|
INTERNAL_ERROR | 500 | Unexpected server error |
DATABASE_ERROR | 500 | Database operation failed |
TRANSACTION_FAILED | 500 | Database transaction failed |
Error Handling Best Practices
1. Always Check HTTP Status Codes
bash
# Check the HTTP status code in the response
STATUS=$(curl -s -o response.json -w "%{http_code}" \
-X GET https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123 \
-H "Authorization: Bearer DIALOGUE_DB_API_KEY")
case $STATUS in
400)
echo "Invalid request: $(jq -r '.error.message' response.json)"
;;
404)
echo "Resource not found: $(jq -r '.error.code' response.json)"
;;
429)
RETRY_AFTER=$(grep -i 'retry-after' headers.txt | awk '{print $2}')
echo "Rate limited. Retry after ${RETRY_AFTER}s"
sleep "$RETRY_AFTER"
;;
500)
echo "Server error. Request ID: $(jq -r '.error.requestId' response.json)"
;;
esactypescript
const response = await fetch(url, options);
if (!response.ok) {
const error = await response.json();
switch (response.status) {
case 400:
// Validation error - fix request
console.error('Invalid request:', error.error.message);
break;
case 404:
// Not found - handle missing resource
console.error('Resource not found:', error.error.code);
break;
case 429:
// Rate limited - retry with backoff
await sleep(parseInt(response.headers.get('Retry-After')!) * 1000);
return retry();
case 500:
// Server error - retry or alert
console.error('Server error:', error.error.requestId);
break;
}
}python
import requests
response = requests.get(
"https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123",
headers={"Authorization": "Bearer DIALOGUE_DB_API_KEY"}
)
if not response.ok:
error = response.json()["error"]
if response.status_code == 400:
# Validation error - fix request
print(f"Invalid request: {error['message']}")
elif response.status_code == 404:
# Not found - handle missing resource
print(f"Resource not found: {error['code']}")
elif response.status_code == 429:
# Rate limited - retry with backoff
retry_after = int(response.headers.get("Retry-After", 1))
time.sleep(retry_after)
# retry...
elif response.status_code == 500:
# Server error - retry or alert
print(f"Server error: {error['requestId']}")typescript
import { DialogueDB, DialogueDBError } from 'dialogue-db';
const db = new DialogueDB({ apiKey: 'DIALOGUE_DB_API_KEY' });
try {
const dialogue = await db.getDialogue('dlg_abc123');
} catch (error) {
if (error instanceof DialogueDBError) {
switch (error.statusCode) {
case 400:
console.error('Invalid request:', error.message);
break;
case 404:
console.error('Resource not found:', error.code);
break;
case 429:
// Rate limited - SDK handles retries automatically
break;
case 500:
console.error('Server error:', error.requestId);
break;
}
}
}2. Use Error Codes for Logic
bash
# Attempt to get a dialogue, create if not found
RESPONSE=$(curl -s -w "\n%{http_code}" \
-X GET https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123 \
-H "Authorization: Bearer DIALOGUE_DB_API_KEY")
BODY=$(echo "$RESPONSE" | sed '$d')
STATUS=$(echo "$RESPONSE" | tail -1)
ERROR_CODE=$(echo "$BODY" | jq -r '.error.code // empty')
if [ "$ERROR_CODE" = "DIALOGUE_NOT_FOUND" ]; then
# Create new dialogue
curl -s -X POST https://api.dialoguedb.com/api/v1/dialogue \
-H "Authorization: Bearer DIALOGUE_DB_API_KEY" \
-H "Content-Type: application/json" \
-d '{"projectId": "proj_123"}'
elif [ "$ERROR_CODE" = "RATE_LIMIT_EXCEEDED" ]; then
echo "Rate limited. Retrying..."
sleep 1
fitypescript
const response = await fetch(
'https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123',
{ headers: { 'Authorization': 'Bearer DIALOGUE_DB_API_KEY' } }
);
if (!response.ok) {
const { error } = await response.json();
if (error.code === 'DIALOGUE_NOT_FOUND') {
// Create new dialogue
return fetch('https://api.dialoguedb.com/api/v1/dialogue', {
method: 'POST',
headers: {
'Authorization': 'Bearer DIALOGUE_DB_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({ projectId: 'proj_123' }),
});
}
if (error.code === 'RATE_LIMIT_EXCEEDED') {
await sleep(1000);
return retry();
}
throw new Error(error.message);
}python
import requests
response = requests.get(
"https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123",
headers={"Authorization": "Bearer DIALOGUE_DB_API_KEY"}
)
if not response.ok:
error = response.json()["error"]
if error["code"] == "DIALOGUE_NOT_FOUND":
# Create new dialogue
response = requests.post(
"https://api.dialoguedb.com/api/v1/dialogue",
headers={
"Authorization": "Bearer DIALOGUE_DB_API_KEY",
"Content-Type": "application/json",
},
json={"projectId": "proj_123"},
)
elif error["code"] == "RATE_LIMIT_EXCEEDED":
time.sleep(1)
# retry...
else:
raise Exception(error["message"])typescript
try {
const dialogue = await db.getDialogue(dialogueId);
} catch (error) {
if (error.code === 'DIALOGUE_NOT_FOUND') {
// Create new dialogue
return db.createDialogue({ projectId: 'proj_123' });
}
if (error.code === 'RATE_LIMIT_EXCEEDED') {
// Wait and retry
await sleep(1000);
return retry();
}
// Unknown error - propagate
throw error;
}3. Handle Validation Errors with Details
bash
# Send an invalid request and parse validation details
RESPONSE=$(curl -s -X POST https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123/messages \
-H "Authorization: Bearer DIALOGUE_DB_API_KEY" \
-H "Content-Type: application/json" \
-d '{"messages": [{"role": "user", "content": ""}]}')
ERROR_TYPE=$(echo "$RESPONSE" | jq -r '.error.type')
if [ "$ERROR_TYPE" = "validation_error" ]; then
echo "$RESPONSE" | jq -r '.error.details[]? | "\(.field): \(.message)"'
fitypescript
const response = await fetch(
'https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123/messages',
{
method: 'POST',
headers: {
'Authorization': 'Bearer DIALOGUE_DB_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({ messages: [{ role: 'user', content: '' }] }),
}
);
if (!response.ok) {
const { error } = await response.json();
if (error.type === 'validation_error' && error.details) {
// Show field-level errors to user
error.details.forEach((detail: { field: string; message: string }) => {
console.error(`${detail.field}: ${detail.message}`);
});
}
}python
import requests
response = requests.post(
"https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123/messages",
headers={
"Authorization": "Bearer DIALOGUE_DB_API_KEY",
"Content-Type": "application/json",
},
json={"messages": [{"role": "user", "content": ""}]},
)
if not response.ok:
error = response.json()["error"]
if error["type"] == "validation_error" and "details" in error:
# Show field-level errors to user
for detail in error["details"]:
print(f"{detail['field']}: {detail['message']}")typescript
try {
await dialogue.saveMessage(message);
} catch (error) {
if (error.type === 'validation_error' && error.details) {
// Show field-level errors to user
error.details.forEach((detail: { field: string; message: string }) => {
console.error(`${detail.field}: ${detail.message}`);
});
}
}4. Log Request IDs for Support
bash
# Capture and log the request ID from error responses
RESPONSE=$(curl -s -X DELETE https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123 \
-H "Authorization: Bearer DIALOGUE_DB_API_KEY")
ERROR_CODE=$(echo "$RESPONSE" | jq -r '.error.code // empty')
if [ -n "$ERROR_CODE" ]; then
REQUEST_ID=$(echo "$RESPONSE" | jq -r '.error.requestId')
MESSAGE=$(echo "$RESPONSE" | jq -r '.error.message')
echo "Operation failed"
echo " Request ID: $REQUEST_ID"
echo " Code: $ERROR_CODE"
echo " Message: $MESSAGE"
echo "Contact support with Request ID: $REQUEST_ID"
fitypescript
const response = await fetch(
'https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123',
{
method: 'DELETE',
headers: { 'Authorization': 'Bearer DIALOGUE_DB_API_KEY' },
}
);
if (!response.ok) {
const { error } = await response.json();
// Always log requestId for debugging
console.error('Operation failed', {
requestId: error.requestId,
code: error.code,
message: error.message,
});
// Show friendly message to user, provide requestId for support
alert(`Operation failed. Please contact support with ID: ${error.requestId}`);
}python
import requests
response = requests.delete(
"https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123",
headers={"Authorization": "Bearer DIALOGUE_DB_API_KEY"}
)
if not response.ok:
error = response.json()["error"]
# Always log requestId for debugging
print(f"Operation failed:")
print(f" Request ID: {error['requestId']}")
print(f" Code: {error['code']}")
print(f" Message: {error['message']}")
print(f"Contact support with Request ID: {error['requestId']}")typescript
try {
await api.dialogue.remove({ id: dialogueId });
} catch (error) {
// Always log requestId for debugging
console.error('Operation failed', {
requestId: error.requestId,
code: error.code,
message: error.message,
});
// Show friendly message to user, provide requestId for support
alert(`Operation failed. Please contact support with ID: ${error.requestId}`);
}5. Implement Retry Logic for Transient Errors
bash
# Retry with exponential backoff
MAX_RETRIES=3
ATTEMPT=0
while [ $ATTEMPT -lt $MAX_RETRIES ]; do
RESPONSE=$(curl -s -o response.json -w "%{http_code}" \
-X GET https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123 \
-H "Authorization: Bearer DIALOGUE_DB_API_KEY")
if [ "$RESPONSE" -lt 400 ]; then
cat response.json
break
fi
ERROR_CODE=$(jq -r '.error.code // empty' response.json)
# Only retry on rate limits and server errors
if [ "$ERROR_CODE" = "RATE_LIMIT_EXCEEDED" ] || [ "$RESPONSE" -ge 500 ]; then
DELAY=$(( 1 << ATTEMPT )) # 1, 2, 4 seconds
[ $DELAY -gt 10 ] && DELAY=10
echo "Retrying in ${DELAY}s (attempt $((ATTEMPT + 1))/$MAX_RETRIES)..."
sleep $DELAY
ATTEMPT=$((ATTEMPT + 1))
else
# Don't retry validation or not found errors
cat response.json
break
fi
donetypescript
async function withRetry<T>(
fn: () => Promise<Response>,
maxRetries = 3
): Promise<Response> {
let lastError: Error | undefined;
for (let i = 0; i < maxRetries; i++) {
const response = await fn();
if (response.ok) {
return response;
}
const { error } = await response.json();
lastError = new Error(error.message);
// Only retry on rate limits and server errors
if (error.code === 'RATE_LIMIT_EXCEEDED' || error.type === 'server') {
const delay = Math.min(1000 * Math.pow(2, i), 10000);
await new Promise((resolve) => setTimeout(resolve, delay));
continue;
}
// Don't retry validation or not found errors
throw lastError;
}
throw lastError;
}
// Usage
const response = await withRetry(() =>
fetch('https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123', {
headers: { 'Authorization': 'Bearer DIALOGUE_DB_API_KEY' },
})
);python
import time
import requests
def with_retry(fn, max_retries=3):
last_error = None
for i in range(max_retries):
response = fn()
if response.ok:
return response
error = response.json()["error"]
last_error = Exception(error["message"])
# Only retry on rate limits and server errors
if error["code"] == "RATE_LIMIT_EXCEEDED" or error["type"] == "server":
delay = min(2 ** i, 10)
time.sleep(delay)
continue
# Don't retry validation or not found errors
raise last_error
raise last_error
# Usage
response = with_retry(lambda: requests.get(
"https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123",
headers={"Authorization": "Bearer DIALOGUE_DB_API_KEY"},
))typescript
async function withRetry<T>(
fn: () => Promise<T>,
maxRetries = 3
): Promise<T> {
let lastError;
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
lastError = error;
// Only retry on rate limits and server errors
if (error.code === 'RATE_LIMIT_EXCEEDED' || error.type === 'server') {
const delay = Math.min(1000 * Math.pow(2, i), 10000);
await new Promise((resolve) => setTimeout(resolve, delay));
continue;
}
// Don't retry validation or not found errors
throw error;
}
}
throw lastError;
}
// Usage
const dialogue = await withRetry(() => db.getDialogue(id));6. Handle Immutability Gracefully
bash
RESPONSE=$(curl -s -o response.json -w "%{http_code}" \
-X DELETE https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123/messages/msg_456 \
-H "Authorization: Bearer DIALOGUE_DB_API_KEY")
if [ "$RESPONSE" = "409" ]; then
ERROR_CODE=$(jq -r '.error.code' response.json)
if [ "$ERROR_CODE" = "DIALOGUE_IMMUTABLE" ]; then
echo "Cannot modify messages in immutable dialogues"
echo "Consider creating a new dialogue with corrected messages"
fi
fitypescript
const response = await fetch(
'https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123/messages/msg_456',
{
method: 'DELETE',
headers: { 'Authorization': 'Bearer DIALOGUE_DB_API_KEY' },
}
);
if (!response.ok) {
const { error } = await response.json();
if (error.code === 'DIALOGUE_IMMUTABLE') {
console.error('Cannot modify messages in immutable dialogues');
console.log('Consider creating a new dialogue with corrected messages');
}
}python
import requests
response = requests.delete(
"https://api.dialoguedb.com/api/v1/dialogue/dlg_abc123/messages/msg_456",
headers={"Authorization": "Bearer DIALOGUE_DB_API_KEY"}
)
if not response.ok:
error = response.json()["error"]
if error["code"] == "DIALOGUE_IMMUTABLE":
print("Cannot modify messages in immutable dialogues")
print("Consider creating a new dialogue with corrected messages")typescript
try {
await dialogue.deleteMessage(messageId);
} catch (error) {
if (error.code === 'DIALOGUE_IMMUTABLE') {
console.error('Cannot modify messages in immutable dialogues');
console.log('Consider creating a new dialogue with corrected messages');
}
}SDK Error Handling
When using the official SDK, errors are automatically parsed into DialogueDBError instances with typed properties:
typescript
import { DialogueDB, DialogueDBError } from 'dialogue-db';
const db = new DialogueDB({ apiKey: 'DIALOGUE_DB_API_KEY' });
try {
await db.getDialogue('invalid_id');
} catch (error) {
if (error instanceof DialogueDBError) {
console.log(error.code); // 'DIALOGUE_NOT_FOUND'
console.log(error.type); // 'not_found'
console.log(error.statusCode); // 404
console.log(error.requestId); // 'req_xyz'
console.log(error.message); // Human-readable message
}
}Testing Error Scenarios
Trigger Validation Errors
bash
# Missing required field
curl -X POST https://api.dialoguedb.com/api/v1/dialogue \
-H "Authorization: Bearer DIALOGUE_DB_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
# Response: 400 with MISSING_PARAMETERTrigger Not Found Errors
bash
# Non-existent dialogue
curl -X GET https://api.dialoguedb.com/api/v1/dialogue/invalid_id \
-H "Authorization: Bearer DIALOGUE_DB_API_KEY"
# Response: 404 with DIALOGUE_NOT_FOUNDTrigger Rate Limit Errors
bash
# Exceed rate limits
for i in {1..100}; do
curl -X GET https://api.dialoguedb.com/api/v1/dialogue \
-H "Authorization: Bearer DIALOGUE_DB_API_KEY"
done
# Response: 429 with RATE_LIMIT_EXCEEDEDDebugging Tips
1. Use Request IDs
Every error includes a requestId. Provide this when contacting support:
Support Request:
- Request ID: req_abc123xyz
- Error Code: INTERNAL_ERROR
- Timestamp: 2025-11-06T21:34:21Z2. Enable Debug Logging
typescript
const client = new DialogueDB({
apiKey: 'DIALOGUE_DB_API_KEY',
debug: true // Log all requests and responses
});3. Check Response Headers
Rate limit information is in headers:
typescript
const response = await fetch(url, options);
console.log('Rate Limit:', response.headers.get('X-RateLimit-Limit'));
console.log('Remaining:', response.headers.get('X-RateLimit-Remaining'));
console.log('Reset:', response.headers.get('X-RateLimit-Reset'));Common Errors & Solutions
| Error | Cause | Solution |
|---|---|---|
DIALOGUE_NOT_FOUND | Dialogue doesn't exist or belongs to different project | Verify dialogue ID and project access |
MESSAGE_CONTENT_EMPTY | Empty message content | Ensure content field is not empty |
TOO_MANY_MESSAGES | More than messages on creation | Split into multiple requests |
DIALOGUE_IMMUTABLE | Project has immutability enabled | Check project settings or create new dialogue |
RATE_LIMIT_EXCEEDED | Too many requests | Implement exponential backoff |
PLAN_LIMIT_EXCEEDED | Plan quota exceeded | Upgrade plan - reads still work, only writes blocked |
PROJECT_NOT_FOUND | Invalid project ID | Verify project exists and is accessible |
Support
If you encounter unexpected errors:
- Check the error code against this reference
- Note the
requestIdfrom the error response - Contact support with the request ID and error details
- Include relevant code that triggered the error
For real-time support:
- Email: support@dialoguedb.com
- Discord: Join our community
- Docs: https://docs.dialoguedb.com

