Troubleshooting - digitalunconciousness/shiftledger GitHub Wiki
A guide to diagnosing and resolving common ShiftLedger issues.
-
systemctl status shiftledgershowsfailedorinactive - App unreachable at
http://localhost:3000
# Check service status
systemctl status shiftledger
# View recent logs
journalctl -u shiftledger --no-pager -n 50Port already in use:
Error: listen EADDRINUSE: address already in use :::3000
Another process is using port 3000. Find and kill it:
lsof -i :3000
kill <PID>
sudo systemctl restart shiftledgerOr change the port in the systemd unit file (see Configuration).
Node.js not found:
ExecStart=/usr/bin/node: No such file or directory
Node.js isn't installed or is installed at a different path:
which node # find the actual path
node -v # verify it worksUpdate the ExecStart path in the service file if needed.
Permission denied on database:
SqliteError: unable to open database file
The shiftledger user can't read/write the database:
ls -la /opt/shiftledger/shifts.db
chown shiftledger:shiftledger /opt/shiftledger/shifts.db
chmod 644 /opt/shiftledger/shifts.dbMissing npm dependencies:
Error: Cannot find module 'express'
Dependencies weren't installed:
cd /opt/shiftledger
sudo -u shiftledger npm install --omit=dev
sudo systemctl restart shiftledgerSqliteError: database is locked- API returns 500 errors intermittently
SQLite allows only one writer at a time. This can happen if:
- A backup is running while the app is writing
- Multiple Node.js processes are accessing the same database
- The WAL file is corrupted
Check for multiple processes:
ps aux | grep "node.*server.js"
# There should be exactly one processIf there are duplicates, kill the extras:
sudo systemctl stop shiftledger
pkill -f "node.*server.js"
sudo systemctl start shiftledgerReset WAL:
sudo systemctl stop shiftledger
sqlite3 /opt/shiftledger/shifts.db "PRAGMA wal_checkpoint(TRUNCATE);"
sudo systemctl start shiftledgerNuclear option — rebuild WAL:
sudo systemctl stop shiftledger
sqlite3 /opt/shiftledger/shifts.db "VACUUM;"
sudo systemctl start shiftledgerPossible causes:
-
SESSION_SECRET changed — if the secret was regenerated (e.g., service restarted without a stable secret in the unit file), all existing session cookies become invalid.
- Fix: Ensure
SESSION_SECRETis set to a stable value in the systemd unit file. - Users will need to log in again.
- Fix: Ensure
-
Cookie not being sent — if accessing via a different domain/port than expected, the browser may not send the cookie.
- Check browser dev tools → Application → Cookies for
sl_session.
- Check browser dev tools → Application → Cookies for
-
Session expired — sessions last 30 days. After that, users must log in again.
You're hitting POST /api/auth/setup but an admin already exists. Use POST /api/auth/login instead.
There's no password reset UI. Reset via the database directly:
# Generate a new hash (using Node.js)
node -e "
const crypto = require('crypto');
const salt = crypto.randomBytes(16).toString('hex');
crypto.scrypt('newpassword', salt, 64, (err, key) => {
console.log(salt + ':' + key.toString('hex'));
});
"
# Update the database
sudo systemctl stop shiftledger
sqlite3 /opt/shiftledger/shifts.db "UPDATE users SET password_hash = '<hash_from_above>' WHERE username = 'admin';"
sudo systemctl start shiftledgerIf you need to start fresh with authentication:
sudo systemctl stop shiftledger
sqlite3 /opt/shiftledger/shifts.db "DELETE FROM sessions; DELETE FROM users;"
sudo systemctl start shiftledger
# Visit the app — you'll see the first-run setup screen againWarning: This deletes all user accounts. Shifts are preserved but will show "Unknown" for the user.
- App crashes on startup with SQL errors
- Log shows
Running migration v<N>followed by an error
Check the current schema version:
sqlite3 /opt/shiftledger/shifts.db "SELECT value FROM meta WHERE key = 'db_version';"Table already exists:
All migrations use CREATE TABLE IF NOT EXISTS, so this shouldn't happen. If it does, the meta table's version number may be wrong:
# Check actual tables
sqlite3 /opt/shiftledger/shifts.db ".tables"
# Manually set version if tables exist
sqlite3 /opt/shiftledger/shifts.db "INSERT OR REPLACE INTO meta (key, value) VALUES ('db_version', '4');"Column already exists:
The v1 migration uses PRAGMA table_info() to check before adding columns, but if manually altered:
sqlite3 /opt/shiftledger/shifts.db "PRAGMA table_info(shifts);"
# Verify the columns match what the migration expectsIf migrations are broken, the safest approach is:
- Back up the database:
cp shifts.db shifts.db.backup - Delete the database:
rm shifts.db - Restart ShiftLedger — it will create a fresh database
- Import your data from CSV backup (if available)
SQLite should handle thousands of shifts without any perceptible delay. If things are slow:
- Check database size:
ls -lh /opt/shiftledger/shifts.db- Check for WAL bloat:
ls -lh /opt/shiftledger/shifts.db-wal
# If this is very large (>100 MB), checkpoint it:
sqlite3 /opt/shiftledger/shifts.db "PRAGMA wal_checkpoint(TRUNCATE);"- Optimize the database:
sudo systemctl stop shiftledger
sqlite3 /opt/shiftledger/shifts.db "VACUUM; ANALYZE;"
sudo systemctl start shiftledger- Check system resources:
free -h # memory
df -h # disk space
top -b -n 1 | head -20 # CPU/memory usageThe Node.js process typically uses 30–50 MB. If it's much higher:
- Check for a memory leak with
node --inspect server.js - Restart the service as a workaround:
sudo systemctl restart shiftledger
- Ensure
pdfkitis installed:npm ls pdfkitin/opt/shiftledger - Check logs for errors during PDF generation
- Try exporting a smaller date range
- PDF respects the date range filters — make sure
fromandtoquery params are correct - Soft-deleted shifts are excluded from exports
The file needs at least 2 lines (header + one data row).
- Check date format — must be
YYYY-MM-DD - Verify column order matches the export format
- Ensure numeric fields don't have currency symbols (
$15.00won't parse — use15.00) - Check for encoding issues (UTF-8 required)
All imported shifts are assigned to the currently logged-in user. There's no way to import as a different user through the UI.
- Check that localStorage is enabled in your browser
- Try clearing localStorage: browser dev tools → Application → Local Storage → Clear
- Chart.js is loaded from CDN. Check browser console for network errors.
- If offline, charts won't load (the CDN script isn't cached by the service worker)
- Ensure you're accessing via HTTPS (required for PWA installation, except on localhost)
- Check that
manifest.jsonis accessible: visit/manifest.jsonin the browser - Clear the service worker: browser dev tools → Application → Service Workers → Unregister
- Shortcuts are disabled when a text input or textarea is focused
- Check that no browser extensions are intercepting the key combinations
- Press
?to verify the shortcut overlay appears
When reporting an issue, include:
# App version
cat /opt/shiftledger/package.json | grep version
# Node version
node -v
# OS info
cat /etc/os-release
# Service status
systemctl status shiftledger
# Recent logs (last 100 lines)
journalctl -u shiftledger --no-pager -n 100
# Database version
sqlite3 /opt/shiftledger/shifts.db "SELECT * FROM meta;"
# Database size
ls -lh /opt/shiftledger/shifts.db*