Skip to content

Troubleshooting Guide

Solutions to common issues when developing and deploying ImageBot.

Error:

error imagebot@0.0.1: The engine "node" is incompatible with this module.

Solution:

Terminal window
# Check Node version
node --version
# Should be 18.x or higher
# Install Node 18+ if needed
nvm install 18
nvm use 18

Error:

Error: Failed to login. Please try again.

Solution:

Terminal window
# Clear Wrangler cache
rm -rf ~/.wrangler
# Try login again
wrangler login
# If still fails, use API token
wrangler login --api-key YOUR_API_KEY

Error:

npm ERR! ERESOLVE unable to resolve dependency tree

Solution:

Terminal window
# Clear npm cache
npm cache clean --force
# Delete node_modules and package-lock.json
rm -rf node_modules package-lock.json
# Reinstall with legacy peer deps
npm install --legacy-peer-deps

Error:

SQLITE_ERROR: no such column: team_id at offset 69

Solution: Use the minimal schema versions that avoid foreign key constraints:

Terminal window
# Use teams-minimal.sql instead of teams-schema.sql
wrangler d1 execute imagebot-db --remote --file database/teams-minimal.sql

Why: Cloudflare D1 has limitations with ALTER TABLE and complex foreign key constraints.

Error:

Error: Database binding 'DB' not found

Solution:

  1. Verify database exists:
Terminal window
wrangler d1 list
  1. Check wrangler.toml has correct binding:
[[d1_databases]]
binding = "DB"
database_name = "imagebot-db"
database_id = "your-database-id-here"
  1. Ensure you’re running worker dev server:
Terminal window
npm run worker:dev

Error:

Error: table 'users' already exists

Solution:

Option 1: Use IF NOT EXISTS in schema (already included in schema-init.sql)

CREATE TABLE IF NOT EXISTS users (...)

Option 2: Drop and recreate (⚠️ DELETES ALL DATA):

Terminal window
# Export data first
wrangler d1 export imagebot-db --output backup.sql
# Delete and recreate database
wrangler d1 delete imagebot-db
wrangler d1 create imagebot-db
# Apply schema
wrangler d1 execute imagebot-db --remote --file database/schema-init.sql

Error:

Error: Script startup exceeded CPU time limit

Solution:

  1. Remove unnecessary imports:
// Remove heavy libraries not used in production
// Check worker/index.ts for large dependencies
  1. Optimize initialization:
// Move heavy operations out of global scope
// Lazy load modules only when needed
  1. Check bundle size:
Terminal window
wrangler publish --dry-run --outdir=dist
ls -lh dist

Error (Browser Console):

Access to fetch at 'https://worker.dev/api/generate' from origin 'http://localhost:4321'
has been blocked by CORS policy

Solution:

Update worker/index.ts CORS headers:

const corsHeaders = {
'Access-Control-Allow-Origin': '*', // Or specific origin
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
};
// Handle OPTIONS preflight
if (request.method === 'OPTIONS') {
return new Response(null, { headers: corsHeaders });
}
// Add to all responses
return new Response(JSON.stringify(data), {
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
});

Error:

{"error": "Unauthorized"}

Solution:

  1. Check JWT token is being sent:
// In browser console
localStorage.getItem('token')
  1. Verify Authorization header:
fetch('https://worker.dev/api/images', {
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`
}
})
  1. Check token hasn’t expired:
// Decode JWT (payload is middle part)
const payload = JSON.parse(atob(token.split('.')[1]));
console.log('Expires:', new Date(payload.exp * 1000));
  1. Verify JWT_SECRET is set:
Terminal window
wrangler secret list

Error: Changes to worker code don’t appear after deployment.

Solution:

  1. Clear Cloudflare cache:
Terminal window
# Purge cache via API
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache" \
-H "Authorization: Bearer API_TOKEN" \
-d '{"purge_everything":true}'
  1. Hard refresh browser:
  • Chrome: Cmd+Shift+R (Mac) or Ctrl+Shift+R (Windows)
  1. Check deployment succeeded:
Terminal window
wrangler tail imagebot-worker
# Trigger request and watch for logs

Error:

TypeError: Cannot read property 'get' of undefined

Solution:

  1. Create .env file:
Terminal window
cp .env.example .env
  1. Set API URL:
Terminal window
PUBLIC_API_URL=http://localhost:8787
  1. Restart dev server:
Terminal window
npm run dev

Error: Images show broken image icon or 404.

Solution:

  1. Check R2 bucket exists:
Terminal window
wrangler r2 bucket list
  1. Verify R2 binding in wrangler.toml:
[[r2_buckets]]
binding = "IMAGES"
bucket_name = "imagebot-images"
  1. Configure R2 public access or custom domain:
Terminal window
# Option 1: Custom domain
wrangler r2 bucket domain add imagebot-images --domain images.yourdomain.com
# Option 2: Public bucket
wrangler r2 bucket cors put imagebot-images --allow-origin '*'
  1. Update r2_url generation in worker/index.ts:
const r2Url = `https://images.yourdomain.com/${r2Key}`;
// Or use R2 dev URL for testing
const r2Url = `https://imagebot-images.r2.dev/${r2Key}`;

Error: Components render but have no styling.

Solution:

  1. Verify Tailwind config includes all content paths:
tailwind.config.mjs
export default {
content: [
'./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'
],
// ...
}
  1. Import Tailwind in layout:
src/layouts/Layout.astro
---
import '../styles/global.css';
---
  1. Rebuild:
Terminal window
npm run build

Error:

{"error": "Invalid credentials"}

Solution:

  1. Check database has user:
Terminal window
wrangler d1 execute imagebot-db --remote --command \
"SELECT id, email FROM users WHERE email = 'user@example.com'"
  1. Verify password was hashed during registration:
Terminal window
wrangler d1 execute imagebot-db --remote --command \
"SELECT password_hash FROM users WHERE email = 'user@example.com'"
# Should be a long bcrypt hash starting with $2a$ or $2b$
  1. Test bcrypt in isolation:
const bcrypt = require('bcryptjs');
const hash = await bcrypt.hash('mypassword', 10);
console.log(await bcrypt.compare('mypassword', hash)); // Should be true

Error: Logged out after a few minutes.

Solution:

Update JWT expiration in worker/index.ts:

const token = await jwt.sign({
userId: user.id,
exp: Math.floor(Date.now() / 1000) + (60 * 60 * 24 * 30) // 30 days instead of 7
}, env.JWT_SECRET);

Error:

{"error": "Invalid signature"}

Solution:

  1. Verify webhook secret:
Terminal window
wrangler secret list
# Should show STRIPE_WEBHOOK_SECRET
  1. Test webhook signature:
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const signature = request.headers.get('stripe-signature');
const event = stripe.webhooks.constructEvent(
rawBody,
signature,
process.env.STRIPE_WEBHOOK_SECRET
);
  1. Check Stripe Dashboard:
  • Go to Developers → Webhooks
  • Verify endpoint URL matches your Worker
  • Check webhook logs for errors

Error:

{"error": "Payment failed"}

Solution:

  1. Use Stripe test cards:
  • Success: 4242 4242 4242 4242
  • Decline: 4000 0000 0000 0002
  • Requires auth: 4000 0025 0000 3155
  1. Check Stripe logs:
Terminal window
stripe logs tail
  1. Verify amount is in cents:
// Correct
amount: 999, // $9.99
// Wrong
amount: 9.99, // Invalid

Symptom: Images take 10+ seconds to generate.

Solution:

  1. Use faster models:
// Fast models
'@cf/black-forest-labs/flux-1-schnell' // Fastest
'@cf/stabilityai/stable-diffusion-xl-base-1.0' // Fast
// Slower models (higher quality)
'@cf/runwayml/stable-diffusion-v1-5'
  1. Reduce image size:
{
prompt: "...",
model: "...",
num_steps: 4, // Lower steps = faster (min 4 for Flux)
guidance: 7.5 // Default
}
  1. Check AI model availability:
Terminal window
# Some models may have queue times
curl https://api.cloudflare.com/client/v4/accounts/ACCOUNT_ID/ai/models \
-H "Authorization: Bearer API_TOKEN"

Symptom: Gallery takes long time to load with many images.

Solution:

  1. Implement pagination (already in code):
// Frontend should paginate
const images = await api.get(`/api/images?limit=20&offset=${page * 20}`);
  1. Enable lazy loading (already in code via react-lazy-load-image-component)

  2. Optimize R2 image delivery:

  • Use Cloudflare Image Resizing
  • Enable CDN caching
  • Compress images before upload

Error:

{"error": "Rate limit exceeded. Try again in 60 seconds."}

Solution:

  1. Implement exponential backoff:
async function retryWithBackoff(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (error.status === 429 && i < maxRetries - 1) {
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, i)));
} else {
throw error;
}
}
}
}
  1. Check rate limit headers:
const response = await fetch('...');
console.log('Rate limit:', response.headers.get('X-RateLimit-Remaining'));
  1. Upgrade plan or request limit increase

Error:

Error: listen EADDRINUSE: address already in use :::4321

Solution:

Terminal window
# Find process using port
lsof -i :4321
# Kill process
kill -9 PID
# Or use different port
npm run dev -- --port 3000

Symptom: Frontend calls API endpoint that doesn’t exist.

Solution:

  1. Ensure both are running:
Terminal window
# Terminal 1
npm run dev
# Terminal 2
npm run worker:dev
  1. Check API URL matches:
Terminal window
# In .env
PUBLIC_API_URL=http://localhost:8787
# Should match worker dev server port
  1. Clear browser cache and reload

Error:

{"error": "Internal server error"}

Solution:

  1. Check Worker logs:
Terminal window
wrangler tail imagebot-worker --status error
  1. Review error details:
// Add better error logging in worker
try {
// ... code
} catch (error) {
console.error('Error details:', error);
return new Response(JSON.stringify({
error: 'Internal server error',
details: error.message // Only in development
}), { status: 500 });
}
  1. Check Cloudflare dashboard:
  • Workers → imagebot-worker → Metrics
  • Look for error spikes and stack traces

Error:

Error: Query exceeded time limit

Solution:

  1. Add indexes:
CREATE INDEX idx_images_user_created ON images(user_id, created_at DESC);
CREATE INDEX idx_collections_user ON collections(user_id);
  1. Optimize query:
-- Bad: Full table scan
SELECT * FROM images WHERE is_deleted = 0 ORDER BY created_at DESC;
-- Good: Uses index
SELECT * FROM images WHERE user_id = ? AND is_deleted = 0 ORDER BY created_at DESC LIMIT 20;
  1. Use D1 analytics to find slow queries:
  • Dashboard → D1 → imagebot-db → Analytics

If you can’t resolve an issue:

  1. Check logs:

    Terminal window
    # Worker logs
    wrangler tail imagebot-worker
    # Browser console
    Open DevTools Console
  2. Search GitHub issues:

  3. Ask community:

  4. Contact support:

worker/index.ts
const DEBUG = true;
function log(...args: any[]) {
if (DEBUG) {
console.log('[ImageBot]', ...args);
}
}
// Use throughout code
log('Generating image for user:', userId);
log('Prompt:', prompt);
Terminal window
# Test health endpoint
curl https://imagebot-worker.workers.dev/api/health
# Test authenticated endpoint
curl https://imagebot-worker.workers.dev/api/images \
-H "Authorization: Bearer YOUR_TOKEN"
# Test POST request
curl -X POST https://imagebot-worker.workers.dev/api/generate \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"prompt":"test","model":"@cf/black-forest-labs/flux-1-schnell"}'
  1. Open DevTools → Network
  2. Filter by “Fetch/XHR”
  3. Click request to see:
    • Headers (including Authorization)
    • Payload
    • Response
    • Timing
Terminal window
# List all tables
wrangler d1 execute imagebot-db --remote --command \
"SELECT name FROM sqlite_master WHERE type='table'"
# Check table schema
wrangler d1 execute imagebot-db --remote --command \
"PRAGMA table_info(users)"
# Sample data
wrangler d1 execute imagebot-db --remote --command \
"SELECT * FROM images LIMIT 5"