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:
sudo apt-get install build-essential python3
npm rebuild better-sqlite3
Or force rebuild from source:
npm install --build-from-source better-sqlite3
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:
mkdir -p data
chmod 755 data
Ensure sufficient free space (minimum 1GB recommended).
Ensure the application user has write access:
sudo chown -R $USER:$USER data/
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:
The auto-generated quote number will increment on retry.
Implement Transaction Lock (Future Enhancement)
Add database-level locking to quote creation logic:
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:
Check for Multiple Instances
Kill duplicate processes:
pkill -f "next start"
pm2 restart icl-cotizaciones
Close SQLite CLI Sessions
Ensure no active sqlite3 sessions:
sqlite.pragma("busy_timeout = 5000"); // 5 second timeout
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:
pm2 stop icl-cotizaciones
Attempt recovery (data loss likely):
cp data/icl.db data/icl.db.corrupt
sqlite3 data/icl.db.corrupt ".recover" | sqlite3 data/icl.db.recovered
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:
Open Application tab
Navigate to Cookies
Delete icl-session cookie
Refresh page
Navigate to /login and re-authenticate.
Check Session Configuration
Verify src/lib/session.ts has correct password:
password: process.env.SESSION_PASSWORD || "dev-key"
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:
sqlite3 data/icl.db "SELECT full_name, email, role FROM users WHERE email = '[email protected]';"
If user needs elevated permissions:
Available roles: DIRECTOR, GERENTE, COMERCIAL, ADMINISTRACION, OPERACIONES, CSV
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:
npx tsx src/db/migrate-v5.ts
This calculates and populates week for all NULL records.
sqlite3 data/icl.db "SELECT COUNT(*) FROM quotations WHERE week IS NULL;"
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:
Ensure session password is stored in env var, not hardcoded:
export SESSION_PASSWORD="your-secure-key-32-chars-min"
Add to .env.production or systemd service file.
If password must change, inform users they’ll need to re-login.
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:
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);
sqlite3 data/icl.db "ANALYZE;"
Rewrite N+1 queries to use JOINs:
// 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:
node --max-old-space-size=1024 node_modules/next/dist/bin/next start
Use Node.js heap snapshot:
node --inspect node_modules/next/dist/bin/next start
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:
Ensure version matches package.json (5.9.3).
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:
openssl s_client -connect cotizaciones.iclsa.com:443 -servername cotizaciones.iclsa.com
Check certificate expiration:
echo | openssl s_client -connect cotizaciones.iclsa.com:443 2>/dev/null | openssl x509 -noout -dates
Renew Let’s Encrypt Certificate
sudo certbot renew
sudo systemctl reload nginx
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:
Kill conflicting process:
Environment Variables Not Set
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:
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:
- Check application logs for error details
- Verify database integrity:
sqlite3 data/icl.db "PRAGMA integrity_check;"
- Review recent migrations or data imports
- Restore from backup if data corruption suspected
- Contact development team with:
- Error message and stack trace
- Steps to reproduce
- Environment details (Node version, OS)
- Recent changes (deployments, migrations)
Preventive Measures