Troubleshooting Guide
Diagnose and resolve common issues in SonicJS applications with this comprehensive troubleshooting guide.
Overview
This guide covers the most common issues developers encounter when working with SonicJS, organized by category with specific error messages and solutions.
When debugging issues, check the console logs first. SonicJS logs detailed error information that can help identify the root cause quickly.
Authentication Errors
401 - Authentication Required
Error Message: "Authentication required" or "Invalid or expired token"
Causes:
- Missing JWT token in request
- Token not in Authorization header or auth_token cookie
- Malformed Bearer token format
Solutions:
Check Token Format
// Correct format - Authorization header
fetch('/api/content', {
headers: {
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
}
})
// Or use cookies (set by login endpoint)
fetch('/api/content', {
credentials: 'include' // Include cookies in request
})
401 - Expired Token
Error Message: "Your session has expired, please login again"
Causes:
- Token's
exptimestamp has passed - Default token lifetime is 24 hours
Solutions:
Refresh Token
// Call refresh endpoint before token expires
const response = await fetch('/auth/refresh', {
method: 'POST',
credentials: 'include'
})
if (response.ok) {
// New token automatically set in cookie
console.log('Token refreshed')
} else {
// Redirect to login
window.location.href = '/admin/login'
}
403 - Insufficient Permissions
Error Message: "Insufficient permissions"
Causes:
- User role doesn't match required role for endpoint
- Trying to access admin endpoints without admin role
Solutions:
- Verify the user has the correct role assigned
- Check the endpoint's required role in the route definition
- Use the correct role when creating users:
User Roles
// Available roles (most to least privileged)
const roles = ['admin', 'editor', 'author', 'viewer']
// Create user with specific role
await db.prepare(`
INSERT INTO users (email, password, role)
VALUES (?, ?, ?)
`).bind(email, hashedPassword, 'editor').run()
Login Failures
Error Message: "Invalid email or password"
Causes:
- Incorrect password
- Email not found in database
- Email case sensitivity issues
Solutions:
- Verify email is normalized to lowercase
- Check password meets minimum requirements (8+ characters)
- Use password reset if credentials are lost
Email Normalization
// SonicJS normalizes emails to lowercase
const normalizedEmail = email.toLowerCase().trim()
// Ensure consistency when checking credentials
Database Errors
409 - Duplicate Content Slug
Error Message: "A content item with this slug already exists in this collection"
Causes:
- Attempting to create content with a slug that already exists
- Slug uniqueness is enforced per collection
Solutions:
Generate Unique Slug
// Auto-generate unique slug
function generateUniqueSlug(title: string, existingSlugs: string[]): string {
let slug = title
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/(^-|-$)/g, '')
let counter = 1
let uniqueSlug = slug
while (existingSlugs.includes(uniqueSlug)) {
uniqueSlug = `${slug}-${counter}`
counter++
}
return uniqueSlug
}
400 - Duplicate User
Error Message: "User with this email or username already exists"
Causes:
- Email already registered
- Username already taken
Solutions:
- Check if user exists before registration
- Provide clear feedback to users about which field is duplicate
Check Existing User
// Check before registration
const existing = await db
.prepare('SELECT id FROM users WHERE email = ? OR username = ?')
.bind(email.toLowerCase(), username)
.first()
if (existing) {
return c.json({ error: 'User already exists' }, 400)
}
404 - Content Not Found
Error Message: "Content not found"
Causes:
- Invalid content ID
- Content was deleted
- Looking in wrong collection
Solutions:
- Verify the content ID is correct
- Check that content hasn't been soft-deleted
- Ensure you're querying the correct collection
UNIQUE Constraint Failed
Error Message: "UNIQUE constraint failed: [table].[column]"
Causes:
- Database-level uniqueness violation
- Migration re-running with existing data
Solutions:
Handle Constraint Errors
try {
await db.prepare('INSERT INTO users (email) VALUES (?)').bind(email).run()
} catch (error) {
if (error.message.includes('UNIQUE constraint failed')) {
// Handle duplicate gracefully
return c.json({ error: 'Email already exists' }, 400)
}
throw error
}
Cache Issues
Cache Not Working
Symptoms:
- Data not being cached
- Stale data being served
- High database load
Causes:
- KV binding not configured
- Cache disabled in settings
- Cache keys not matching
Solutions:
Verify Cache Configuration
# wrangler.toml - Ensure KV binding exists
[[kv_namespaces]]
binding = "CACHE_KV"
id = "your-kv-namespace-id"
Check Cache Status
// Verify cache is working
const cacheService = new CacheService(env.CACHE_KV)
// Test cache operations
await cacheService.set('test-key', { value: 'test' }, 60)
const result = await cacheService.get('test-key')
if (!result) {
console.error('Cache write/read failed')
}
Cache Invalidation Issues
Symptoms:
- Old data persists after updates
- Changes not reflected immediately
Solutions:
- Content updates automatically invalidate related cache keys
- Force invalidation after custom operations:
Manual Cache Invalidation
import { CacheInvalidationService } from '@sonicjs-cms/core/plugins'
const invalidation = new CacheInvalidationService(env.CACHE_KV)
// Invalidate content cache
await invalidation.invalidateContent(contentId)
// Invalidate user cache
await invalidation.invalidateUser(userId)
// Invalidate collection cache
await invalidation.invalidateCollection(collectionId)
Memory Cache Overflow
Symptoms:
- Memory usage increasing
- Worker crashes on memory limits
Solutions:
- Memory cache defaults to 50MB limit with LRU eviction
- Use KV cache for production workloads
- Configure appropriate TTLs:
Cache TTL Configuration
// Short TTL for frequently changing data
await cache.set('user-session', data, 300) // 5 minutes
// Longer TTL for stable content
await cache.set('collection-schema', schema, 3600) // 1 hour
// Very long TTL for static assets
await cache.set('site-config', config, 86400) // 24 hours
Email & Notification Errors
Email Plugin Not Available
Error Message: "Email plugin not available"
Causes:
- Email plugin not enabled
- SendGrid API key not configured
Solutions:
Configure Email
# wrangler.toml
[vars]
DEFAULT_FROM_EMAIL = "[email protected]"
DEFAULT_FROM_NAME = "Your App"
# Set API key as secret
# npx wrangler secret put SENDGRID_API_KEY
OTP Email Failed
Error Message: "Failed to send OTP email" or "Error sending OTP email"
Causes:
- Email service not configured
- SendGrid API key invalid
- From email not verified in SendGrid
Solutions:
- Verify SendGrid API key has Mail Send permission
- Verify sender domain/email in SendGrid
- Check email plugin is enabled:
Enable Email Plugin
// In admin: Plugins > Enable Email Templates
// Or programmatically:
const settings = await getPluginSettings('email-templates')
console.log('Email enabled:', settings.enabled)
Email Template Not Found
Causes:
- Template slug doesn't exist
- Template is inactive
Solutions:
Check Template
// List available templates
const templates = await db
.prepare('SELECT slug, name, is_active FROM email_templates')
.all()
console.log('Available templates:', templates.results)
// Ensure template is active
await db
.prepare('UPDATE email_templates SET is_active = 1 WHERE slug = ?')
.bind('welcome-email')
.run()
Plugin Errors
Plugin Installation Failed
Error Message: "Failed to install plugin [name]"
Causes:
- Invalid plugin configuration
- Conflicting table names
- Reserved plugin name used
Solutions:
Validate Plugin
import { PluginValidator } from '@sonicjs-cms/core/plugins'
const validation = PluginValidator.validate(myPlugin)
if (!validation.valid) {
console.error('Plugin validation errors:', validation.errors)
// Fix issues before installing
}
Reserved Names
Reserved plugin names (cannot be used):
core,system,admin,api,auth,content,media,users,collections
Reserved table names (cannot be used by plugins):
users,collections,content,content_versions,media,api_tokens
Plugin Name Validation
Error Message: "Invalid plugin name"
Requirements:
- Must match pattern:
/^[a-z0-9-]+$/ - Lowercase letters, numbers, and hyphens only
- No spaces or special characters
Valid Plugin Names
// Valid
'my-plugin'
'analytics-v2'
'custom-auth'
// Invalid
'MyPlugin' // No uppercase
'my plugin' // No spaces
'my_plugin' // No underscores
Hook Recursion Detected
Error Message: "Hook recursion detected"
Causes:
- Hook handler triggers the same hook
- Circular hook dependencies
Solutions:
Prevent Recursion
// Bad - causes recursion
hooks.register('content:save', async (data) => {
// This triggers content:save again!
await db.prepare('UPDATE content SET ...').run()
return data
})
// Good - use flag to prevent recursion
hooks.register('content:save', async (data, context) => {
if (context.fromHook) return data
// Safe to update with flag
await db.prepare('UPDATE content SET ...').run()
return data
})
Collection Errors
Invalid Collection Config
Error Message: "Invalid collection config: missing required fields"
Required fields:
name- Collection identifierdisplayName- Human-readable nameschema- Field definitions
Valid Collection Config
import { defineCollection } from '@sonicjs-cms/core'
export default defineCollection({
name: 'blog_posts', // Required
displayName: 'Blog Posts', // Required
schema: { // Required
title: { type: 'string', required: true },
content: { type: 'richtext' }
}
})
Collection Name Validation
Error Message: "Collection name must contain only lowercase letters, numbers, underscores, and hyphens"
Requirements:
- Must match pattern:
/^[a-z0-9_-]+$/ - No uppercase letters
- No spaces
Valid Collection Names
// Valid
'blog_posts'
'user-profiles'
'faq'
// Invalid
'BlogPosts' // No uppercase
'blog posts' // No spaces
'blog.posts' // No dots
Bootstrap & Startup
Bootstrap Errors
Symptoms:
- App starts but features don't work
- Collections not synced
- Migrations not applied
Solutions:
Bootstrap errors are caught but logged. Check console for:
- Collection sync failures
- Migration errors
- Plugin initialization failures
Manual Bootstrap
// Force re-bootstrap on specific errors
import { runMigrations } from '@sonicjs-cms/core'
// Re-run migrations
await runMigrations(db)
// Re-sync collections
await collectionSync.syncAll()
First Admin User
Issue: Cannot log in, no admin user exists
Solutions:
Create Admin User
# Set initial admin via environment
# wrangler.toml or secrets
ADMIN_EMAIL=[email protected]
ADMIN_PASSWORD=your-secure-password
Or create via API (if registration is enabled):
Create Admin via API
curl -X POST https://your-app.workers.dev/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"password": "your-secure-password",
"username": "admin"
}'
Debug Tools
Logging Service
SonicJS includes a comprehensive logging service:
Using the Logger
import { Logger } from '@sonicjs-cms/core'
const logger = new Logger(db, {
level: 'debug', // debug, info, warn, error, fatal
category: 'my-feature'
})
// Log with context
logger.debug('Processing request', { userId, action })
logger.info('Operation completed', { duration: Date.now() - start })
logger.error('Operation failed', { error: error.message })
View Logs
Query Logs
// Get recent logs
const logs = await db
.prepare(`
SELECT * FROM logs
WHERE created_at > datetime('now', '-1 hour')
ORDER BY created_at DESC
LIMIT 100
`)
.all()
// Filter by category
const authLogs = await db
.prepare(`
SELECT * FROM logs
WHERE category = 'auth'
ORDER BY created_at DESC
`)
.all()
Debug Mode
Enable debug mode for verbose logging:
Enable Debug
# wrangler.toml
[env.development.vars]
ENVIRONMENT = "development"
DEBUG = "true"
Plugin Debugging
Each plugin gets a namespaced logger:
Plugin Logging
// In your plugin
builder.setLogger((msg, level) => {
console.log(`[Plugin:my-plugin] [${level}] ${msg}`)
})
Error Reference
HTTP Status Codes
| Code | Meaning | Common Causes |
|---|---|---|
| 400 | Bad Request | Validation failed, missing fields, invalid JSON |
| 401 | Unauthorized | No token, invalid token, expired token |
| 403 | Forbidden | Insufficient role/permissions |
| 404 | Not Found | Resource doesn't exist |
| 409 | Conflict | Duplicate slug, unique constraint violation |
| 500 | Server Error | Unhandled exception, database error |
Error Response Format
All API errors return a consistent format:
Error Response
{
"error": "Human-readable error message",
"details": "Technical details (in development)",
"code": "ERROR_CODE"
}
Common Error Codes
| Code | Message | Solution |
|---|---|---|
AUTH_REQUIRED | Authentication required | Add valid JWT token |
AUTH_EXPIRED | Token expired | Refresh or re-login |
AUTH_INVALID | Invalid credentials | Check email/password |
PERM_DENIED | Insufficient permissions | Check user role |
NOT_FOUND | Resource not found | Verify ID/slug |
DUPLICATE | Already exists | Use unique value |
VALIDATION | Validation failed | Check required fields |
Getting Help
If you're still stuck:
- Check GitHub Issues: Search for similar problems at github.com/lane711/sonicjs/issues
- Join Discord: Get help from the community
- Open an Issue: Report bugs with reproduction steps