Skip to main content

Cold Starts

Problem: First TTS request after inactivity takes 15-30 seconds and may timeout. Cause: Modal provisions a GPU container on-demand. The Chatterbox model is ~3GB and takes time to load into VRAM.
Configure your HTTP client to allow longer timeouts for the first request:
src/lib/chatterbox.ts
import createClient from "openapi-fetch";

const client = createClient({
  baseUrl: env.CHATTERBOX_API_URL,
  headers: {
    "X-Api-Key": env.CHATTERBOX_API_KEY,
  },
  // Increase timeout for cold starts
  signal: AbortSignal.timeout(45000), // 45 seconds
});
Or handle cold starts gracefully in your UI:
try {
  const audio = await generateSpeech(prompt, voiceKey);
} catch (error) {
  if (error.name === 'TimeoutError') {
    // Retry after cold start
    const audio = await generateSpeech(prompt, voiceKey);
  }
}
Send periodic health checks to prevent scale-down:
// cron job or background task
setInterval(async () => {
  await fetch(env.CHATTERBOX_API_URL + "/docs", {
    headers: { "X-Api-Key": env.CHATTERBOX_API_KEY },
  });
}, 4 * 60 * 1000); // Every 4 minutes (before 5min scaledown)
This increases Modal costs but ensures sub-second response times. The scale-down window is configured at chatterbox_tts.py:85.
Adjust the scaledown_window in chatterbox_tts.py:
chatterbox_tts.py
@app.cls(
    gpu="a10g",
    scaledown_window=60 * 15,  # 15 minutes instead of 5
    secrets=[...],
)
Redeploy with modal deploy chatterbox_tts.py.
Problem: modal deploy fails with authentication or permission errors. Solutions:
1

Check Authentication

modal setup
Re-authenticate with your Modal account.
2

Verify Secrets Exist

modal secret list
Ensure cloudflare-r2, chatterbox-api-key, and hf-token are present.
3

Check R2 Credentials in Script

Verify R2_BUCKET_NAME and R2_ACCOUNT_ID in chatterbox_tts.py:23-24 match your Cloudflare R2 setup exactly.

Voice Not Found Error

Problem: Modal returns Voice not found at 'voices/system/...'. Cause: The R2 bucket mount can’t find the voice file, or the path is incorrect.
Check your R2 bucket contains the voice files:
# Using AWS CLI with R2
aws s3 ls s3://your-bucket-name/voices/system/ \
  --endpoint-url https://your-account-id.r2.cloudflarestorage.com
System voices should be seeded by npx prisma db seed.
Verify voices have r2ObjectKey populated:
npx prisma studio
Look at the Voice table. Each voice should have an r2ObjectKey like voices/system/<id> or voices/custom/<id>.
npx prisma db seed
This uploads all 20 system voices from scripts/system-voices/*.wav to R2 and updates the database.
Problem: Modal returns 403 Invalid API key. Solution: The X-Api-Key header must match the CHATTERBOX_API_KEY secret in Modal:
# Update the secret
modal secret create chatterbox-api-key \
  CHATTERBOX_API_KEY="your-new-key" \
  --force

# Update your app's environment variable
CHATTERBOX_API_KEY="your-new-key"
Redeploy Modal: modal deploy chatterbox_tts.py

Database Issues

Migration Fails

Problem: npx prisma migrate deploy fails with connection errors.
Verify the connection string format:
# Should look like:
postgresql://user:password@host:5432/database?sslmode=require

# Test connection
npx prisma db execute --stdin <<< "SELECT 1;"
Most managed Postgres providers require SSL:
DATABASE_URL="postgresql://...?sslmode=require"
Prisma Postgres uses connection pooling by default. Other providers may need:
# With pgBouncer or Supabase pooler
DATABASE_URL="postgresql://...?pgbouncer=true"

Prisma Client Not Generated

Problem: Import errors for @prisma/client or generated types. Solution: The postinstall script should run automatically, but you can trigger it manually:
npx prisma generate
The client is generated to src/generated/prisma/client (configured in prisma/schema.prisma:8).

Seed Script Fails

Problem: npx prisma db seed fails with R2 upload errors.
1

Check R2 Credentials

Verify R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, and R2_BUCKET_NAME are correct.
2

Test R2 Connection

# Using AWS CLI
aws s3 ls s3://your-bucket-name \
  --endpoint-url https://your-account-id.r2.cloudflarestorage.com \
  --profile r2
3

Verify WAV Files Exist

Check scripts/system-voices/*.wav files are present in your repository. These should be included in the repo.

R2 Storage Issues

Audio Upload Fails

Problem: Custom voice cloning fails with “Failed to upload audio” error.
R2 bucket needs CORS enabled for client uploads (if using presigned URLs):
[
  {
    "AllowedOrigins": ["https://yourdomain.com"],
    "AllowedMethods": ["GET", "PUT", "POST"],
    "AllowedHeaders": ["*"],
    "MaxAgeSeconds": 3600
  }
]
Apply in Cloudflare R2 dashboard under bucket settings.
The R2 API token needs these permissions:
  • Object Read
  • Object Write
  • Object Delete (optional, for cleanup)
Create a new token in Cloudflare dashboard if needed.
Next.js proxy has a 20MB body size limit (configured in next.config.ts:8). Audio files must be under this limit.The voice cloning requires at least 10 seconds of audio. Typical WAV files are 1-5MB.

Audio Playback Fails

Problem: Generated audio won’t play in browser.
Resonance proxies audio through /api/audio/[id] to avoid CORS issues. Verify:
curl https://yourdomain.com/api/audio/generation-id -I
Should return Content-Type: audio/wav or audio/mpeg.
Check the database Generation record has a valid r2ObjectKey, and the object exists in R2:
aws s3 ls s3://your-bucket/generations/ \
  --endpoint-url https://your-account-id.r2.cloudflarestorage.com
Some browsers are strict about audio MIME types. The WAV files from Chatterbox should have:
  • Content-Type: audio/wav
  • Valid WAV header (22050 Hz sample rate)
Check browser console for codec errors.

Build & Runtime Issues

Build Fails: Environment Validation

Problem: Build fails with “Invalid environment variables” error. Solution: All required env vars must be set at build time. The validation schema is in src/lib/env.ts:5-20.
# Check which variables are missing
npm run build

# Set SKIP_ENV_VALIDATION for build-only scenarios
SKIP_ENV_VALIDATION=true npm run build
Skipping validation is not recommended for production. It will cause runtime errors if vars are actually missing.

Runtime Error: tRPC Procedure Failed

Problem: tRPC mutations fail with generic error messages.
The actual error is logged server-side. Check your hosting platform’s logs:
# Railway
railway logs

# Docker
docker logs resonance

# Vercel
vercel logs
  • Database connection failed: Check DATABASE_URL
  • R2 credentials invalid: Verify R2 env vars
  • Modal timeout: See Cold Starts
  • Clerk session invalid: User needs to re-authenticate

Clerk Organizations Not Working

Problem: Users can’t create organizations or see org-specific data.
1

Enable Organizations in Clerk

Go to Clerk Dashboard → Settings → Organizations → Enable
2

Verify Middleware

Clerk middleware must be configured to protect routes. Check middleware.ts exists and includes:
export default clerkMiddleware();
3

Check orgId in Requests

All tRPC procedures use auth().orgId to scope data. If this is null, the user isn’t in an organization context.

Performance Issues

Slow TTS Generation

Problem: Audio generation takes longer than expected (>10 seconds after warm start). Causes:
  • Long text: Chatterbox processes ~50 characters/second. 500 characters = ~10 seconds.
  • High parameters: Lower temperature, top_k, or repetition_penalty for faster generation.
  • Modal concurrency: If max_inputs=10 is reached, requests queue.
// Faster generation (less creative)
const audio = await generateSpeech(prompt, voiceKey, {
  temperature: 0.5,     // default: 0.8
  top_k: 500,          // default: 1000
});
Increase max_inputs in chatterbox_tts.py:
@modal.concurrent(max_inputs=20)  # default: 10
Redeploy: modal deploy chatterbox_tts.py

High Memory Usage

Problem: Next.js app uses excessive memory or crashes. Solution: The Prisma client and tRPC context can accumulate in memory. Use connection pooling and limit concurrent requests:
next.config.ts
const nextConfig: NextConfig = {
  experimental: {
    proxyClientMaxBodySize: "20mb",
    // Add memory management
    workerThreads: false,
    cpus: 1,
  },
};
Or increase memory limit:
# In your hosting platform
NODE_OPTIONS="--max-old-space-size=2048"

Getting Help

GitHub Issues

Report bugs or request features

Deployment Overview

Review prerequisites and architecture
For Modal-specific issues, check Modal’s documentation or their Discord community.

Build docs developers (and LLMs) love