Troubleshooting
Common issues and solutions when using Vettly.
Authentication Issues
"Invalid API key" Error
Symptoms: 401 error, VettlyAuthError
Causes:
- Wrong API key
- Using test key (
sk_test_...) in production - Key was revoked or deleted
Solutions:
- Check the key in your dashboard
- Ensure environment variable is set correctly
- Verify no extra whitespace in the key
- Create a new key if the old one was compromised
# Check your key is set
echo $VETTLY_API_KEY
# Common issue: extra newline
export VETTLY_API_KEY="sk_live_xxxxx" # Use quotesAPI Key Not Loading
Symptoms: Empty or undefined API key
Solutions:
// Use server-side env (no NEXT_PUBLIC_ prefix)
const client = new ModerationClient({
apiKey: process.env.VETTLY_API_KEY! // Not NEXT_PUBLIC_
})// Client-side needs VITE_ prefix
const client = new ModerationClient({
apiKey: import.meta.env.VITE_VETTLY_API_KEY
})import os
# Check env is loaded
api_key = os.environ.get("VETTLY_API_KEY")
if not api_key:
raise ValueError("VETTLY_API_KEY not set")
client = ModerationClient(api_key=api_key)Rate Limiting
"Rate limit exceeded" Error
Symptoms: 429 error, VettlyRateLimitError
Causes:
- Too many requests per second
- Burst of traffic exceeded limits
Solutions:
Check your limits in the dashboard
Implement client-side throttling:
import pLimit from 'p-limit'
const limit = pLimit(10) // Max 10 concurrent requests
const results = await Promise.all(
items.map(item => limit(() => client.check({
content: item.text,
policyId: 'moderate',
contentType: 'text'
})))
)- Use batch endpoints for bulk operations:
const result = await client.batchCheck({
policyId: 'moderate',
items: items.map(item => ({
id: item.id,
content: item.text
}))
})- Upgrade your plan for higher limits
Retry-After Header
The SDK automatically respects Retry-After headers. If implementing manual retries:
try {
await client.check({ ... })
} catch (error) {
if (error instanceof VettlyRateLimitError) {
const waitTime = error.retryAfter || 1
await sleep(waitTime * 1000)
// Retry...
}
}Quota Issues
"Quota exceeded" Error
Symptoms: 402 error, VettlyQuotaError
Causes:
- Monthly API call limit reached
- Plan limit exceeded
Solutions:
- Check usage in dashboard
- Upgrade your plan
- Implement caching for repeated content
const cache = new Map<string, CheckResponse>()
async function checkWithCache(content: string) {
const hash = crypto.createHash('md5').update(content).digest('hex')
if (cache.has(hash)) {
return cache.get(hash)!
}
const result = await client.check({
content,
policyId: 'moderate',
contentType: 'text'
})
cache.set(hash, result)
return result
}Content Issues
Content Too Large
Symptoms: 422 error, request rejected
Limits:
- Text: 32KB (approximately 8,000 words)
- Images: 20MB
- Video: 100MB
Solutions:
- Truncate long text:
const MAX_LENGTH = 30000 // ~30KB
const truncated = content.length > MAX_LENGTH
? content.substring(0, MAX_LENGTH)
: content
await client.check({
content: truncated,
policyId: 'moderate',
contentType: 'text'
})Compress images before sending
Use chunk-based processing for very long content
Invalid Content Type
Symptoms: 422 error mentioning content type
Solutions:
- Ensure
contentTypematches the actual content - For images, use
data:image/...format or valid URL - For base64, include the data URL prefix
// Wrong
client.check({
content: rawBase64, // Missing data URL prefix
contentType: 'image'
})
// Correct
client.check({
content: `data:image/jpeg;base64,${rawBase64}`,
contentType: 'image'
})Timeout Issues
Request Timeout
Symptoms: Timeout error, no response
Causes:
- Large content taking too long
- Network issues
- API under high load
Solutions:
- Increase timeout:
const client = new ModerationClient({
apiKey: 'sk_live_...',
timeout: 60000 // 60 seconds
})- Use async batch for large operations:
const { batchId } = await client.batchCheckAsync({
policyId: 'moderate',
items: largeItemList,
webhookUrl: 'https://myapp.com/webhook'
})
// Results delivered via webhookWebhook Issues
Webhooks Not Receiving Events
Symptoms: No webhook deliveries
Checklist:
- Webhook URL is publicly accessible
- URL uses HTTPS
- Endpoint responds with 2xx status
- Webhook is enabled in dashboard
Test your endpoint:
// Send test event
await client.testWebhook(webhookId, 'decision.blocked')Invalid Signature
Symptoms: Signature verification fails
Common issues:
- Wrong webhook secret
- Modifying payload before verification
- Using wrong encoding
Correct implementation:
// Get raw body BEFORE any parsing
app.post('/webhooks/vettly',
express.raw({ type: 'application/json' }),
(req, res) => {
const payload = req.body.toString() // Raw string
const signature = req.headers['x-vettly-signature']
if (!verifyWebhookSignature(payload, signature, secret)) {
return res.status(401).send('Invalid signature')
}
// Now parse
const event = constructWebhookEvent(payload)
// ...
}
)Webhook Timeout
Symptoms: Webhook marked as failed, retrying
Solutions:
- Respond within 5 seconds
- Process events asynchronously
app.post('/webhooks/vettly', async (req, res) => {
// Verify signature...
const event = constructWebhookEvent(payload)
// Respond immediately
res.status(200).send('OK')
// Process async
await processEventAsync(event)
})SDK-Specific Issues
TypeScript: Module Not Found
Error: Cannot find module '@nextauralabs/vettly-sdk'
Solutions:
# Clear and reinstall
rm -rf node_modules package-lock.json
npm installPython: Import Error
Error: ModuleNotFoundError: No module named 'vettly'
Solutions:
# Ensure correct Python version
python3 -m pip install vettly
# Or with virtual env
source venv/bin/activate
pip install vettlyPython: Async Issues
Error: RuntimeError: Event loop is already running
Solution: Use the async client properly:
# Wrong: mixing sync and async
client = ModerationClient(...)
await client.check(...) # ModerationClient is sync!
# Correct: use AsyncModerationClient
async with AsyncModerationClient(api_key="...") as client:
result = await client.check(content="...", policy_id="moderate")Getting Help
If you're still stuck:
- Check Status: status.vettly.dev
- Search Issues: GitHub Issues
- Ask Community: GitHub Discussions
- Contact Support: support@vettly.dev
When reporting issues, include:
- SDK version (
vettly --versionor check package.json) - Error message and stack trace
- Minimal reproduction code
- Decision ID if available