Error Handling
This guide covers error handling and troubleshooting for the Logstyx API.
Understanding Logstyx Error Handling
Asynchronous Processing Model
Logstyx uses an asynchronous architecture where:
- Gateway Layer: Accepts HTTP requests and performs basic validation
- Message Queue: Queues logs for reliable processing
- Consumer Layer: Processes logs asynchronously and validates authorization
This means most validation and authorization errors occur after the HTTP response is sent.
HTTP Responses
All successful HTTP requests return 200 OK with the following response:
{
"status": "queued"
}This indicates the log has been queued for processing, not that it has been successfully stored.
Why This Design?
This architecture provides several benefits:
- High availability: System can accept logs even during backend processing issues
- Better performance: Clients don't wait for full processing
- Resilience: Logs are queued and won't be lost during temporary failures
- Prevents retry storms: Clients don't retry on authorization failures
The Trade-off
The downside is that you cannot immediately verify if your log was successfully processed. You must check your Logstyx dashboard to confirm logs are being stored.
HTTP Error Responses
While most requests return 200 OK, you will receive error status codes for infrastructure-level issues.
Rate Limiting Errors
429 Too Many Requests
Cause: Exceeded the rate limit of 20 requests per second per IP address.
Response Example:
HTTP/1.1 429 Too Many RequestsSolution:
// Implement exponential backoff
async function sendLogWithRetry(logData, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await sendLog(logData);
return response;
} catch (error) {
if (error.response?.status === 429) {
const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s
console.log(`Rate limited. Retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
throw new Error('Max retries exceeded');
}Best Practices:
- Implement client-side batching to reduce request frequency
- Add exponential backoff for retries
- Monitor your request rate and adjust accordingly
- Consider using a queue on the client side
503 Service Unavailable
Cause: Request burst exceeded the configured limit (50 requests).
Response Example:
HTTP/1.1 503 Service UnavailableSolution: Same as 429 - implement exponential backoff and reduce request frequency.
Validation Errors
These errors occur during asynchronous processing and will not return an HTTP error. The request returns 200 OK, but the log is rejected during processing.
INVALID_INPUT Error
When it occurs:
- Missing required fields (
level,projectId,data) - Invalid
levelvalue (not one of:info,warning,error,critical) - Malformed JSON in request body
- Invalid data types
Common Causes:
- Missing required fields:
// ❌ Wrong - missing 'data' field
{
"level": "info",
"projectId": "proj_123"
}
// ✅ Correct
{
"level": "info",
"projectId": "proj_123",
"data": {
"message": "User logged in"
}
}- Invalid log level:
// ❌ Wrong - invalid level
{
"level": "debug", // Not a valid level
"projectId": "proj_123",
"data": { "message": "Debug info" }
}
// ✅ Correct
{
"level": "info", // Valid: info, warning, error, critical
"projectId": "proj_123",
"data": { "message": "Debug info" }
}How to detect: Check your Logstyx dashboard. If logs aren't appearing, validation may be failing.
Prevention:
// Validate before sending
function validateLogData(logData) {
const validLevels = ['info', 'warning', 'error', 'critical'];
if (!logData.level || !validLevels.includes(logData.level)) {
throw new Error('Invalid log level');
}
if (!logData.projectId || typeof logData.projectId !== 'string') {
throw new Error('Invalid project ID');
}
if (!logData.data || typeof logData.data !== 'object') {
throw new Error('Invalid data field');
}
return true;
}
// Use before sending
try {
validateLogData(myLog);
await sendLog(myLog);
} catch (error) {
console.error('Log validation failed:', error.message);
}Authorization Errors
NO_ACCESS Error
When it occurs:
- Origin not in allowed origins list (browser clients)
- App ID not in allowed app IDs list (mobile clients)
- Signature validation failed (server clients)
- Invalid project ID
Common Causes:
1. Browser Client - Invalid Origin
// If your app runs on https://myapp.com
// but allowed origins only include https://app.myapp.com
// ❌ Request will fail
fetch('https://logstyx.example.com/api/v1/logs', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
// Browser automatically sets Origin: https://myapp.com
},
body: JSON.stringify(logData)
});Solution: Add the origin to your project's allowed origins list in the Logstyx dashboard:
{
"settings": {
"allowedOrigin": [
"https://myapp.com",
"https://app.myapp.com",
"http://localhost:3000" // for development
]
}
}2. Mobile Client - Invalid App ID
// ❌ Wrong - app ID not in allowed list
{
"level": "info",
"projectId": "proj_123",
"appid": "com.mycompany.wrong-app", // Not in allowed list
"data": { "message": "App started" }
}
// ✅ Correct - app ID in allowed list
{
"level": "info",
"projectId": "proj_123",
"appid": "com.mycompany.myapp.ios", // In allowed list
"data": { "message": "App started" }
}Solution: Add the app ID to allowed origins in your project settings.
3. Server Client - Signature Validation Failed
Common signature errors:
- Wrong field order:
// ❌ Wrong order
const payload = {
projectId: body.projectId, // Wrong order
level: body.level,
data: body.data,
device: body.device,
context: body.context
};
// ✅ Correct order
const payload = {
level: body.level,
projectId: body.projectId,
device: body.device,
context: body.context,
data: body.data
};- Signature not uppercase:
// ❌ Wrong
const signature = crypto
.createHmac('SHA256', secret)
.update(hashString)
.digest('hex'); // Lowercase
// ✅ Correct
const signature = crypto
.createHmac('SHA256', secret)
.update(hashString)
.digest('hex')
.toUpperCase(); // Uppercase- Timestamp not converted to integer:
// ❌ Wrong
const timestamp = Date.now();
const hashString = projectId + params + timestamp; // timestamp is float
// ✅ Correct
const timestamp = Date.now();
const hashString = projectId + params + Math.floor(timestamp); // Convert to int- Extra spaces in JSON:
// ❌ Wrong - JSON with spaces
const params = JSON.stringify(payload, null, 2); // Formatted JSON
// ✅ Correct - compact JSON
const params = JSON.stringify(payload); // No extra spaces- Wrong secret:
// Make sure you're using the correct project secret
const projectSecret = process.env.LOGSTYX_PROJECT_SECRET; // From environmentDebug signature generation:
function debugSignature(projectId, projectSecret, body, timestamp) {
const payload = {
level: body.level,
projectId: body.projectId,
device: body.device,
context: body.context,
data: body.data
};
const params = JSON.stringify(payload);
const hashString = projectId + params + Math.floor(timestamp);
console.log('Debug Signature Generation:');
console.log('Project ID:', projectId);
console.log('Payload:', payload);
console.log('Params JSON:', params);
console.log('Timestamp:', timestamp);
console.log('Timestamp (int):', Math.floor(timestamp));
console.log('Hash String:', hashString);
const signature = crypto
.createHmac('SHA256', projectSecret)
.update(hashString)
.digest('hex')
.toUpperCase();
console.log('Generated Signature:', signature);
return signature;
}Network Errors
Connection Errors
Causes:
- Network connectivity issues
- Incorrect endpoint URL
- SSL/TLS certificate problems
- Firewall blocking requests
Example:
try {
await sendLog(logData);
} catch (error) {
if (error.code === 'ECONNREFUSED') {
console.error('Cannot connect to Logstyx server');
console.error('Check if the server is running and endpoint is correct');
} else if (error.code === 'ENOTFOUND') {
console.error('DNS lookup failed - check your endpoint URL');
} else if (error.code === 'CERT_HAS_EXPIRED') {
console.error('SSL certificate expired');
}
}Solutions:
- Verify endpoint URL is correct
- Check network connectivity
- Ensure SSL certificates are valid
- Check firewall rules
Timeout Errors
Causes:
- Slow network connection
- Server overload
- Request timeout set too low
Solution:
// Increase timeout for slow networks
const axios = require('axios');
const response = await axios.post(
'https://your-domain.com/api/v1/logs',
logData,
{
timeout: 10000, // 10 second timeout
headers: {
'Content-Type': 'application/json'
}
}
);Monitoring and Debugging
Check if Logs are Being Received
Since the API returns 200 OK even for invalid logs, you must monitor your Logstyx dashboard:
- Dashboard Check: Log into your Logstyx dashboard and verify logs appear
- Test Log: Send a known test log and verify it appears
- Timeline: Check the timestamp of recent logs to ensure they're current
Test Authentication
Browser Client Test
<!DOCTYPE html>
<html>
<head>
<title>Logstyx Test</title>
</head>
<body>
<button onclick="testLog()">Send Test Log</button>
<div id="result"></div>
<script>
async function testLog() {
try {
const response = await fetch('https://your-domain.com/api/v1/logs', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
level: 'info',
projectId: 'your_project_id',
data: {
message: 'Test log from browser',
testId: Date.now()
}
})
});
const data = await response.json();
document.getElementById('result').innerHTML =
`Status: ${response.status}<br>Response: ${JSON.stringify(data)}`;
alert('Log sent! Check your Logstyx dashboard in a few seconds.');
} catch (error) {
document.getElementById('result').innerHTML =
`Error: ${error.message}`;
}
}
</script>
</body>
</html>Mobile Client Test
// React Native example
import { useLogstyx } from 'logstyx-js-react-native';
function TestLogging() {
const logger = useLogstyx({
projectId: 'your_project_id',
appid: 'com.yourcompany.app',
endpoint: 'https://your-domain.com/api/v1/logs'
});
const testLog = async () => {
await logger.info({
message: 'Test log from mobile',
testId: Date.now()
});
alert('Log sent! Check your Logstyx dashboard in a few seconds.');
};
return (
<Button title="Test Logging" onPress={testLog} />
);
}Server Client Test
const crypto = require('crypto');
const axios = require('axios');
async function testServerLogging() {
const projectId = 'your_project_id';
const projectSecret = 'your_project_secret';
const timestamp = Date.now();
const body = {
level: 'info',
projectId: projectId,
device: 'test-server',
context: { test: true },
data: {
message: 'Test log from server',
testId: timestamp
}
};
// Generate signature
const payload = {
level: body.level,
projectId: body.projectId,
device: body.device,
context: body.context,
data: body.data
};
const params = JSON.stringify(payload);
const hashString = projectId + params + Math.floor(timestamp);
const signature = crypto
.createHmac('SHA256', projectSecret)
.update(hashString)
.digest('hex')
.toUpperCase();
console.log('Test Log Details:');
console.log('Timestamp:', timestamp);
console.log('Signature:', signature);
console.log('Body:', JSON.stringify(body, null, 2));
try {
const response = await axios.post(
'https://your-domain.com/api/v1/logs',
body,
{
headers: {
'Content-Type': 'application/json',
'timestamp': timestamp.toString(),
'signature': signature
}
}
);
console.log('Response:', response.data);
console.log('✅ Log sent successfully! Check your dashboard.');
} catch (error) {
console.error('❌ Error:', error.message);
if (error.response) {
console.error('Status:', error.response.status);
console.error('Data:', error.response.data);
}
}
}
testServerLogging();Common Issues and Solutions
Issue 1: Logs not appearing in dashboard
Symptoms: API returns 200 OK, but logs don't appear in dashboard.
Possible Causes:
- Authentication failure
- Invalid request format
- Asynchronous processing delay
Troubleshooting Steps:
- Wait a moment: Processing is asynchronous; wait 5-10 seconds
- Check authentication:
- Browser: Verify origin is in allowed list
- Mobile: Verify app ID is in allowed list
- Server: Verify signature generation is correct
- Check project ID: Ensure you're using the correct project ID
- Validate request format: Ensure all required fields are present
- Check log level: Must be
info,warning,error, orcritical
Issue 2: Intermittent 429 errors
Symptoms: Occasional 429 Too Many Requests responses.
Cause: Request rate exceeds 20 per second per IP.
Solution:
// Implement a rate limiter
class RateLimitedLogger {
constructor(maxRequestsPerSecond = 15) {
this.maxRPS = maxRequestsPerSecond;
this.queue = [];
this.processing = false;
setInterval(() => this.processQueue(), 1000);
}
async log(logData) {
return new Promise((resolve, reject) => {
this.queue.push({ logData, resolve, reject });
if (!this.processing) {
this.processQueue();
}
});
}
async processQueue() {
this.processing = true;
const batch = this.queue.splice(0, this.maxRPS);
await Promise.all(
batch.map(async ({ logData, resolve, reject }) => {
try {
const result = await sendLog(logData);
resolve(result);
} catch (error) {
reject(error);
}
})
);
this.processing = false;
}
}
const logger = new RateLimitedLogger();Issue 3: CORS errors (browser only)
Symptoms:
Access to fetch at 'https://your-domain.com/api/v1/logs' from origin
'https://yourapp.com' has been blocked by CORS policyCause: Origin not in allowed origins list or CORS not configured on server.
Solution:
- Add origin to allowed origins in project settings
- Ensure Logstyx server CORS is configured correctly
- For development, add
http://localhost:3000to allowed origins
Issue 4: Signature always fails (server clients)
Debug checklist:
- [ ] Field order:
level,projectId,device,context,data - [ ] Signature is uppercase
- [ ] Timestamp converted to integer with
Math.floor() - [ ] JSON has no extra spaces
- [ ] Using correct project secret
- [ ] Both
timestampandsignatureheaders are set
Test with curl:
# Use the debug script from "Server Client Test" section
# to print all values, then manually construct curl commandBest Practices for Error Handling
1. Implement Retry Logic
async function sendLogWithRetry(logData, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
await sendLog(logData);
return;
} catch (error) {
const isRateLimit = error.response?.status === 429 ||
error.response?.status === 503;
const isLastAttempt = attempt === maxRetries - 1;
if (isRateLimit && !isLastAttempt) {
const delay = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
}2. Log Errors Locally
async function safeSendLog(logData) {
try {
await sendLog(logData);
} catch (error) {
// Fallback: log to console in development
if (process.env.NODE_ENV === 'development') {
console.log('Failed to send log:', logData);
console.error('Error:', error.message);
}
// Could also write to local file, local storage, etc.
}
}3. Validate Before Sending
function validateAndSendLog(logData) {
const errors = [];
if (!['info', 'warning', 'error', 'critical'].includes(logData.level)) {
errors.push('Invalid log level');
}
if (!logData.projectId) {
errors.push('Missing project ID');
}
if (!logData.data || typeof logData.data !== 'object') {
errors.push('Invalid data field');
}
if (errors.length > 0) {
throw new Error(`Log validation failed: ${errors.join(', ')}`);
}
return sendLog(logData);
}4. Monitor Success Rate
class LoggerWithMetrics {
constructor() {
this.sent = 0;
this.failed = 0;
}
async send(logData) {
try {
await sendLog(logData);
this.sent++;
} catch (error) {
this.failed++;
throw error;
}
}
getStats() {
const total = this.sent + this.failed;
const successRate = total > 0 ? (this.sent / total) * 100 : 0;
return { sent: this.sent, failed: this.failed, successRate };
}
}Getting Help
If you're still experiencing issues:
- GitHub Issues: Report bugs
- GitHub Discussions: Ask questions
- Documentation: Review main docs
When reporting issues, include:
- Client type (browser/mobile/server)
- Request/response examples
- Any error messages
- Steps to reproduce