Skip to main content

Overview

This guide covers common issues, error messages, and solutions for ICL Cotizaciones.

Installation Issues

Error: Cannot find module ‘better-sqlite3’

Symptoms:
Error: Cannot find module 'better-sqlite3'
    at Module._resolveFilename (node:internal/modules/cjs/loader:1134:15)
Cause: better-sqlite3 is a native module that requires compilation with node-gyp. Build may have failed during npm install. Solution:
1
Install Build Tools
2
On Ubuntu/Debian:
3
sudo apt-get install build-essential python3
4
On macOS:
5
xcode-select --install
6
Rebuild better-sqlite3
7
npm rebuild better-sqlite3
8
Or force rebuild from source:
9
npm install --build-from-source better-sqlite3
10
Clean Install
11
If rebuild fails:
12
rm -rf node_modules package-lock.json
npm install

Error: next build fails with better-sqlite3

Symptoms:
Error: Cannot bundle native module better-sqlite3
Cause: better-sqlite3 is a native module and cannot be bundled by webpack. Solution: Verify next.config.ts includes:
serverExternalPackages: ["better-sqlite3"]
If missing, add it to the Next.js config.

Database Errors

Error: SQLITE_CANTOPEN: unable to open database file

Symptoms:
Error: SQLITE_CANTOPEN: unable to open database file
    at Database.prepare (better-sqlite3)
Cause:
  • Directory data/ does not exist
  • Insufficient file permissions
  • Disk full
Solution:
1
Create Data Directory
2
mkdir -p data
chmod 755 data
3
Check Disk Space
4
df -h
5
Ensure sufficient free space (minimum 1GB recommended).
6
Verify Permissions
7
ls -la data/
8
Ensure the application user has write access:
9
sudo chown -R $USER:$USER data/
10
Test Database Creation
11
sqlite3 data/test.db "CREATE TABLE test (id INTEGER);"
rm data/test.db

Error: UNIQUE constraint failed: quotations.quote_number

Symptoms:
Error: UNIQUE constraint failed: quotations.quote_number
Cause: Race condition in quote number generation. Multiple simultaneous requests created the same COT-YYMM-NNNN number. Solution:
1
Retry the Operation
2
The auto-generated quote number will increment on retry.
3
Implement Transaction Lock (Future Enhancement)
4
Add database-level locking to quote creation logic:
5
const result = db.transaction(() => {
  const lastQuote = getLastQuoteNumber();
  const newNumber = generateNextNumber(lastQuote);
  return insertQuotation({ quote_number: newNumber, ... });
})();

Error: SQLITE_BUSY: database is locked

Symptoms:
Error: SQLITE_BUSY: database is locked
Cause: Another process has an exclusive lock on the database. Solution:
1
Check for Multiple Instances
2
ps aux | grep node
3
Kill duplicate processes:
4
pkill -f "next start"
pm2 restart icl-cotizaciones
5
Close SQLite CLI Sessions
6
Ensure no active sqlite3 sessions:
7
lsof data/icl.db
8
Increase Busy Timeout
9
Add to src/db/index.ts:
10
sqlite.pragma("busy_timeout = 5000"); // 5 second timeout

Error: Database disk image is malformed

Symptoms:
Error: SQLITE_CORRUPT: database disk image is malformed
Cause: Database file corruption due to power failure, disk error, or improper shutdown.
CRITICAL: Restore from backup immediately. Do not attempt to repair.
Solution:
1
Stop Application
2
pm2 stop icl-cotizaciones
3
Restore from Backup
5
If No Backup Available
6
Attempt recovery (data loss likely):
7
cp data/icl.db data/icl.db.corrupt
sqlite3 data/icl.db.corrupt ".recover" | sqlite3 data/icl.db.recovered
8
Verify recovered data:
9
sqlite3 data/icl.db.recovered "SELECT COUNT(*) FROM quotations;"

Authentication Errors

Error: 401 No autorizado

Symptoms: API requests return 401 status code. Cause:
  • Session cookie expired (default TTL not set)
  • Session cookie not sent by browser
  • Session password changed (invalidates all sessions)
Solution:
1
Clear Browser Cookies
2
In browser DevTools:
3
  • Open Application tab
  • Navigate to Cookies
  • Delete icl-session cookie
  • Refresh page
  • 4
    Login Again
    5
    Navigate to /login and re-authenticate.
    6
    Check Session Configuration
    7
    Verify src/lib/session.ts has correct password:
    8
    password: process.env.SESSION_PASSWORD || "dev-key"
    
    9
    If SESSION_PASSWORD env var changed, all users must re-login.

    Error: 403 No autorizado

    Symptoms: API returns 403 status code for admin operations. Cause: Authenticated user lacks required role permissions. Solution:
    1
    Check User Role
    2
    Query database:
    3
    sqlite3 data/icl.db "SELECT full_name, email, role FROM users WHERE email = '[email protected]';"
    
    4
    Update User Role
    5
    If user needs elevated permissions:
    6
    UPDATE users 
    SET role = 'DIRECTOR' 
    WHERE email = '[email protected]';
    
    7
    Available roles: DIRECTOR, GERENTE, COMERCIAL, ADMINISTRACION, OPERACIONES, CSV
    8
    Login with Admin Account
    9
    Use a DIRECTOR or GERENTE account for admin operations.

    Application Errors

    Dashboard shows “Snull” in week axis

    Symptoms: Weekly chart displays “Snull” labels instead of “S12”, “S13”, etc. Cause: Quotations table has week = NULL for records imported before the week column was added. Diagnosis:
    sqlite3 data/icl.db "SELECT COUNT(*) FROM quotations WHERE week IS NULL;"
    
    If count > 0, backfill needed. Solution:
    1
    Run Backfill Migration
    2
    npx tsx src/db/migrate-v5.ts
    
    3
    This calculates and populates week for all NULL records.
    4
    Verify Backfill
    5
    sqlite3 data/icl.db "SELECT COUNT(*) FROM quotations WHERE week IS NULL;"
    
    6
    Expected: 0
    7
    Restart Application
    8
    pm2 restart icl-cotizaciones
    

    Session lost after server restart

    Symptoms: Users logged out after restarting the application. Cause: iron-session uses symmetric encryption. If the session password changes, all existing cookies become invalid. Solution:
    1
    Use Environment Variable
    2
    Ensure session password is stored in env var, not hardcoded:
    3
    export SESSION_PASSWORD="your-secure-key-32-chars-min"
    
    4
    Persist Environment
    5
    Add to .env.production or systemd service file.
    6
    Notify Users
    7
    If password must change, inform users they’ll need to re-login.

    Performance Issues

    Slow query performance

    Symptoms: API requests take > 1 second to respond. Diagnosis: Enable query logging in src/db/index.ts:
    sqlite.on('profile', (sql, time) => {
      if (time > 100) {
        console.log(`[SLOW QUERY ${time}ms]`, sql);
      }
    });
    
    Solution:
    1
    Add Database Indexes
    2
    CREATE INDEX idx_quotations_client ON quotations(client_id);
    CREATE INDEX idx_quotations_status ON quotations(status);
    CREATE INDEX idx_quotations_date ON quotations(date);
    
    3
    Run ANALYZE
    4
    sqlite3 data/icl.db "ANALYZE;"
    
    5
    Optimize Queries
    6
    Rewrite N+1 queries to use JOINs:
    7
    // Before: N+1 queries
    const quotations = await db.select().from(schema.quotations);
    for (const q of quotations) {
      q.client = await db.select().from(schema.clients).where(eq(schema.clients.id, q.client_id));
    }
    
    // After: Single JOIN
    const quotations = await db
      .select()
      .from(schema.quotations)
      .leftJoin(schema.clients, eq(schema.quotations.client_id, schema.clients.id));
    

    High memory usage

    Symptoms: Node.js process exceeds 1GB RAM. Solution:
    1
    Monitor Memory
    2
    pm2 monit
    
    3
    Set Memory Limit
    4
    In PM2 config:
    5
    max_memory_restart: '1G'
    
    6
    Or Node.js flag:
    7
    node --max-old-space-size=1024 node_modules/next/dist/bin/next start
    
    8
    Profile Memory Leaks
    9
    Use Node.js heap snapshot:
    10
    node --inspect node_modules/next/dist/bin/next start
    
    11
    Connect Chrome DevTools to inspect memory.

    Build Errors

    TypeScript errors during build

    Symptoms:
    npm run build
    Type error: Property 'xyz' does not exist on type...
    
    Solution:
    1
    Check TypeScript Version
    2
    npm list typescript
    
    3
    Ensure version matches package.json (5.9.3).
    4
    Regenerate Types
    5
    If using Drizzle schema:
    6
    npm run db:generate
    
    7
    Clear Next.js Cache
    8
    rm -rf .next
    npm run build
    

    Out of memory during build

    Symptoms:
    JavaScript heap out of memory
    
    Solution: Increase Node.js memory:
    NODE_OPTIONS="--max-old-space-size=4096" npm run build
    

    Production Issues

    HTTPS/SSL errors

    Symptoms:
    • Browser shows “Not Secure”
    • Session cookies not sent
    Solution:
    1
    Verify SSL Certificate
    2
    openssl s_client -connect cotizaciones.iclsa.com:443 -servername cotizaciones.iclsa.com
    
    3
    Check certificate expiration:
    4
    echo | openssl s_client -connect cotizaciones.iclsa.com:443 2>/dev/null | openssl x509 -noout -dates
    
    5
    Renew Let’s Encrypt Certificate
    6
    sudo certbot renew
    sudo systemctl reload nginx
    
    7
    Enable Secure Cookies
    8
    In src/lib/session.ts:
    9
    secure: process.env.NODE_ENV === 'production' // must be true for HTTPS
    

    Application not starting

    Symptoms:
    pm2 status shows "errored"
    
    Diagnosis:
    pm2 logs icl-cotizaciones --lines 100
    
    Common Causes:
    1
    Port Already in Use
    2
    Check port 3000:
    3
    lsof -i :3000
    
    4
    Kill conflicting process:
    5
    kill -9 <PID>
    
    6
    Missing Dependencies
    7
    npm install --production
    
    8
    Database File Missing
    9
    npm run db:migrate
    
    10
    Environment Variables Not Set
    11
    Verify .env.production or PM2 config has required vars.

    Data Issues

    Duplicate client records

    Solution: Identify duplicates:
    SELECT legal_name, COUNT(*) as count
    FROM clients
    GROUP BY LOWER(legal_name)
    HAVING count > 1;
    
    Merge duplicates:
    -- Update quotations to reference primary client
    UPDATE quotations
    SET client_id = <primary_id>
    WHERE client_id = <duplicate_id>;
    
    -- Delete duplicate
    DELETE FROM clients WHERE id = <duplicate_id>;
    

    Missing client data after import

    Solution: Re-run enrichment scripts in order:
    npx tsx src/db/link-cotizaciones.ts
    npx tsx src/db/normalize-clients.ts
    npx tsx src/db/enrich-clients.ts
    npx tsx src/db/tag-final-clients.ts
    

    Logging and Debugging

    Enable Debug Logging

    Set environment variable:
    DEBUG=* npm run dev
    
    For production:
    NODE_ENV=production DEBUG=app:* npm start
    

    View Application Logs

    PM2:
    pm2 logs icl-cotizaciones --lines 200
    pm2 logs icl-cotizaciones --err  # errors only
    
    Systemd:
    sudo journalctl -u icl-cotizaciones -f
    sudo journalctl -u icl-cotizaciones --since "1 hour ago"
    
    Docker:
    docker-compose logs -f --tail=100
    

    Database Query Logs

    Enable in src/db/index.ts:
    sqlite.on('profile', (sql, time) => {
      console.log(`[SQL ${time}ms]`, sql);
    });
    

    Getting Help

    If issues persist:
    1. Check application logs for error details
    2. Verify database integrity: sqlite3 data/icl.db "PRAGMA integrity_check;"
    3. Review recent migrations or data imports
    4. Restore from backup if data corruption suspected
    5. Contact development team with:
      • Error message and stack trace
      • Steps to reproduce
      • Environment details (Node version, OS)
      • Recent changes (deployments, migrations)

    Preventive Measures

    • Set up automated daily backups
    • Configure monitoring and alerts
    • Enable error tracking (Sentry, etc.)
    • Implement health check endpoint
    • Document custom deployment procedures
    • Keep dependencies updated
    • Test migrations on staging before production
    • Monitor disk space usage
    • Review logs regularly for warnings
    • Maintain runbook with team-specific procedures

    Build docs developers (and LLMs) love